diff --git a/.github/actions/proxy/configure-proxygen/action.yaml b/.github/actions/proxy/configure-proxygen/action.yaml index 77435569..b25974ed 100644 --- a/.github/actions/proxy/configure-proxygen/action.yaml +++ b/.github/actions/proxy/configure-proxygen/action.yaml @@ -28,14 +28,19 @@ runs: proxygen --version - name: Configure proxygen account details + env: + API_NAME: "${{ inputs.proxygen-api-name }}" + KEY_SECRET: "${{ inputs.proxygen-key-secret }}" + KEY_ID: "${{ inputs.proxygen-key-id }}" + CLIENT_ID: "${{ inputs.proxygen-client-id }}" shell: bash working-directory: proxygen run: | cp settings.template.yaml $HOME/.proxygen/settings.yaml - yq eval '.api = "${{ inputs.proxygen-api-name }}"' -i $HOME/.proxygen/settings.yaml + yq eval '.api = env(API_NAME)' -i $HOME/.proxygen/settings.yaml - printf "%s" "${{ inputs.proxygen-key-secret }}" > /tmp/proxygen_private_key.pem + printf "%s" "$KEY_SECRET" > /tmp/proxygen_private_key.pem cp credentials.template.yaml $HOME/.proxygen/credentials.yaml yq eval '.private_key_path = "/tmp/proxygen_private_key.pem"' -i $HOME/.proxygen/credentials.yaml - yq eval '.key_id = "${{ inputs.proxygen-key-id }}"' -i $HOME/.proxygen/credentials.yaml - yq eval '.client_id = "${{ inputs.proxygen-client-id }}"' -i $HOME/.proxygen/credentials.yaml + yq eval '.key_id = env(KEY_ID)' -i $HOME/.proxygen/credentials.yaml + yq eval '.client_id = env(CLIENT_ID)' -i $HOME/.proxygen/credentials.yaml diff --git a/.github/actions/proxy/deploy-proxy/action.yaml b/.github/actions/proxy/deploy-proxy/action.yaml index e9edb104..9daf5838 100644 --- a/.github/actions/proxy/deploy-proxy/action.yaml +++ b/.github/actions/proxy/deploy-proxy/action.yaml @@ -23,6 +23,9 @@ inputs: proxygen-api-name: description: 'Proxygen API name' required: true + proxygen-environment: + description: 'Proxygen environment' + required: true runs: using: composite @@ -36,13 +39,20 @@ runs: proxygen-api-name: ${{ inputs.proxygen-api-name }} - name: Inject secrets into openapi.yaml for deploying proxy + env: + TARGET_URL: "${{ inputs.target-url }}" + MTLS_SECRET_NAME: "${{ inputs.mtls-secret-name }}" shell: bash run: | cat pathology-api/openapi.yaml proxygen/x-nhsd-apim.template.yaml > /tmp/proxy-specification.yaml - yq eval '.x-nhsd-apim.target.url = "${{ inputs.target-url }}" | .x-nhsd-apim.target.security.secret = "${{ inputs.mtls-secret-name }}"' -i /tmp/proxy-specification.yaml + yq eval '.x-nhsd-apim.target.url = env(TARGET_URL) | .x-nhsd-apim.target.security.secret = env(MTLS_SECRET_NAME)' -i /tmp/proxy-specification.yaml - name: Deploy API proxy + env: + ENVIRONMENT: "${{ inputs.proxygen-environment }}" + BASE_PATH: "${{ inputs.proxy-base-path }}" shell: bash run: | - proxygen instance deploy internal-dev ${{ inputs.proxy-base-path }} /tmp/proxy-specification.yaml --no-confirm + + proxygen instance deploy "$ENVIRONMENT" "$BASE_PATH" /tmp/proxy-specification.yaml --no-confirm diff --git a/.github/actions/proxy/tear-down-proxy/action.yaml b/.github/actions/proxy/tear-down-proxy/action.yaml index eedb5b82..8b405d44 100644 --- a/.github/actions/proxy/tear-down-proxy/action.yaml +++ b/.github/actions/proxy/tear-down-proxy/action.yaml @@ -17,6 +17,9 @@ inputs: proxygen-api-name: description: 'Proxygen API name' required: true + proxygen-environment: + description: 'Proxygen environment' + required: true runs: using: composite @@ -30,6 +33,9 @@ runs: proxygen-api-name: ${{ inputs.proxygen-api-name }} - name: Tear down preview API proxy + env: + ENVIRONMENT: "${{ inputs.proxygen-environment }}" + BASE_PATH: "${{ inputs.proxy-base-path }}" shell: bash run: | - proxygen instance delete internal-dev ${{ inputs.proxy-base-path }} --no-confirm + proxygen instance delete "$ENVIRONMENT" "$BASE_PATH" --no-confirm diff --git a/.github/actions/run-test-suite/action.yaml b/.github/actions/run-test-suite/action.yaml index fa6112e7..d84e9ae5 100644 --- a/.github/actions/run-test-suite/action.yaml +++ b/.github/actions/run-test-suite/action.yaml @@ -26,11 +26,12 @@ runs: env: APIGEE_ACCESS_TOKEN: ${{ inputs.apigee-access-token }} ENV: ${{ inputs.env }} + TEST_TYPE: ${{ inputs.test-type }} run: | if [[ -n "${APIGEE_ACCESS_TOKEN}" ]]; then echo "::add-mask::${APIGEE_ACCESS_TOKEN}" fi - make test-${{ inputs.test-type }} + make test-${TEST_TYPE} - name: "Upload ${{ inputs.test-type }} test results" if: always() @@ -44,8 +45,10 @@ runs: id: check if: always() shell: bash + env: + TEST_TYPE: ${{ inputs.test-type }} run: | - if [[ -f "pathology-api/test-artefacts/${{ inputs.test-type }}-tests.xml" ]]; then + if [[ -f "pathology-api/test-artefacts/${TEST_TYPE}-tests.xml" ]]; then echo "exists=true" >> "$GITHUB_OUTPUT" else echo "exists=false" >> "$GITHUB_OUTPUT" diff --git a/.github/actions/start-local-lambda/action.yaml b/.github/actions/start-local-lambda/action.yaml index f7a8dbcf..5eb0093f 100644 --- a/.github/actions/start-local-lambda/action.yaml +++ b/.github/actions/start-local-lambda/action.yaml @@ -19,7 +19,8 @@ runs: shell: bash env: PYTHON_VERSION: ${{ inputs.python-version }} + DEPLOY_COMMAND: ${{ inputs.deploy-command }} run: | set -euo pipefail - echo "Starting local Lambda: '${{ inputs.deploy-command }}'" - bash -c "${{ inputs.deploy-command }}" + echo "Starting local Lambda: '$DEPLOY_COMMAND'" + bash -c "$DEPLOY_COMMAND" diff --git a/.github/workflows/cicd-1-pull-request.yaml b/.github/workflows/cicd-1-pull-request.yaml index c641f44d..1c9a0b7f 100644 --- a/.github/workflows/cicd-1-pull-request.yaml +++ b/.github/workflows/cicd-1-pull-request.yaml @@ -47,7 +47,7 @@ jobs: run: | branch_name=${GITHUB_HEAD_REF:-$(echo $GITHUB_REF | sed 's#refs/heads/##')} echo "Current branch is '$branch_name'" - if gh pr list --head $branch_name | grep -q .; then + if gh pr list --head "$branch_name" | grep -q .; then echo "Pull request exists" echo "does_pull_request_exist=true" >> $GITHUB_OUTPUT else diff --git a/.github/workflows/integration-env.yaml b/.github/workflows/integration-env.yaml new file mode 100644 index 00000000..354b2210 --- /dev/null +++ b/.github/workflows/integration-env.yaml @@ -0,0 +1,379 @@ +name: Integration Environment + +on: + pull_request: + branches: [integration] + types: [closed] + workflow_dispatch: + +env: + AWS_REGION: eu-west-2 + PREVIEW_PREFIX: int- + PYTHON_VERSION: 3.14 + LAMBDA_RUNTIME: python3.14 + LAMBDA_HANDLER: lambda_handler.handler + MTLS_SECRET_NAME: ${{ vars.PREVIEW_ENV_MTLS_SECRET_NAME }} + PROXYGEN_KEY_ID: ${{ vars.PREVIEW_ENV_PROXYGEN_KEY_ID }} + PROXYGEN_CLIENT_ID: ${{ vars.PREVIEW_ENV_PROXYGEN_CLIENT_ID }} + PROXYGEN_API_NAME: ${{ vars.PROXYGEN_API_NAME }} + BASE_URL: "https://internal-dev.api.service.nhs.uk/${{ vars.PROXYGEN_API_NAME }}-integration" + ENV: "remote" + HOST: "internal-dev.api.service.nhs.uk" + +jobs: + integration-environment: + name: "Deploy Integration Environment" + runs-on: ubuntu-latest + if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true + + permissions: + id-token: write + contents: read + + concurrency: + group: integration-environment + cancel-in-progress: true + + outputs: + function_name: ${{ steps.names.outputs.function_name }} + int_url: ${{ steps.names.outputs.int_url }} + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + ref: integration + + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 + with: + python-version: "${{ env.PYTHON_VERSION }}" + + - name: Setup Python project + uses: ./.github/actions/setup-python-project + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Package artifacts + run: | + make build + + - name: Select AWS role inputs + id: role-select + env: + AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN_INT }} + LAMBDA_ROLE_ARN: ${{ secrets.LAMBDA_ROLE_ARN_INT }} + run: | + echo "aws_role=$AWS_ROLE_ARN" >> "$GITHUB_OUTPUT" + echo "lambda_role=$LAMBDA_ROLE_ARN" >> "$GITHUB_OUTPUT" + + - name: Configure AWS credentials (OIDC) + uses: aws-actions/configure-aws-credentials@5e19c1aa7acd2e02c5110eaf77eacd29039cca28 + with: + role-to-assume: ${{ steps.role-select.outputs.aws_role }} + aws-region: ${{ env.AWS_REGION }} + + - name: Sanitize branch name + id: branch + env: + RAW_BRANCH_NAME: "${{ github.head_ref }}" + run: | + branch=$RAW_BRANCH_NAME + + safe="integration" + + echo "branch=$branch" >> $GITHUB_OUTPUT + echo "safe=$safe" >> $GITHUB_OUTPUT + + - name: Compute function name + id: names + run: | + SAFE=${{ steps.branch.outputs.safe }} + PREFIX=${{ env.PREVIEW_PREFIX }} + MAX_FN_LEN=62 + MAX_PREFIX_LEN=${#PREFIX} + MAX_SAFE_LEN=$((MAX_FN_LEN - MAX_PREFIX_LEN)) + if [ ${#SAFE} -gt "$MAX_SAFE_LEN" ]; then + SAFE=${SAFE:0:MAX_SAFE_LEN} + fi + FN="${PREFIX}${SAFE}" + + echo "function_name=$FN" >> "$GITHUB_OUTPUT" + URL="https://${SAFE}.int.endpoints.${{ env.PROXYGEN_API_NAME }}.national.nhs.uk" + echo "int_url=$URL" >> "$GITHUB_OUTPUT" + + # ---------- Handle application with int ---------- + - name: Create or update preview Lambda with int + env: + MOCK_URL: ${{ steps.names.outputs.int_url }} + TOKEN_EXPIRY_THRESHOLD: ${{ secrets.APIM_TOKEN_EXPIRY_THRESHOLD }} + JWKS_SECRET_NAME: ${{ secrets.JWKS_SECRET }} + APIM_PRIVATE_KEY: ${{ secrets.APIM_PRIVATE_KEY }} + APIM_APIKEY: ${{ secrets.APIM_APIKEY }} + API_MTLS_CERT: ${{ secrets.API_MTLS_CERT }} + API_MTLS_KEY: ${{ secrets.API_MTLS_KEY }} + APIM_KEY_ID: ${{ secrets.APIM_KEY_ID }} + CLIENT_REQUEST_TIMEOUT: ${{ secrets.CLIENT_REQUEST_TIMEOUT }} + run: | + cd pathology-api/target/ + FN="${{ steps.names.outputs.function_name }}" + EXPIRY_THRESHOLD="${TOKEN_EXPIRY_THRESHOLD:-30s}" + JWKS_SECRET="${JWKS_SECRET_NAME:-/cds/pathology/int/jwks/secret}" + PRIVATE_KEY="${APIM_PRIVATE_KEY:-/cds/pathology/int/apim/private-key}" + API_KEY="${APIM_APIKEY:-/cds/pathology/int/apim/api-key}" + MTLS_CERT="${API_MTLS_CERT:-/cds/pathology/int/mtls/client1-key-public}" + MTLS_KEY="${API_MTLS_KEY:-/cds/pathology/int/mtls/client1-key-secret}" + KEY_ID="${APIM_KEY_ID:-DEV-1}" + CLIENT_TIMEOUT="${CLIENT_REQUEST_TIMEOUT:-10s}" + echo "Deploying preview function: $FN" + wait_for_lambda_ready() { + while true; do + status=$(aws lambda get-function-configuration --function-name "$FN" \ + --query 'LastUpdateStatus' \ + --output text 2>/dev/null || echo "Unknown") + if [ "$status" = "Successful" ] || [ "$status" = "Unknown" ]; then + break + fi + if [ "$status" = "Failed" ]; then + echo "Lambda is in Failed state; check logs." >&2 + exit 1 + fi + echo "Lambda update status: $status — waiting..." + sleep 5 + done + } + if aws lambda get-function --function-name "$FN" >/dev/null 2>&1; then + wait_for_lambda_ready + aws lambda update-function-configuration --function-name "$FN" \ + --handler "${{ env.LAMBDA_HANDLER }}" \ + --memory-size 512 \ + --timeout 30 \ + --environment "Variables={APIM_TOKEN_EXPIRY_THRESHOLD=$EXPIRY_THRESHOLD, \ + APIM_PRIVATE_KEY_NAME=$PRIVATE_KEY, \ + APIM_API_KEY_NAME=$API_KEY, \ + APIM_MTLS_CERT_NAME=$MTLS_CERT, \ + APIM_MTLS_KEY_NAME=$MTLS_KEY, \ + APIM_KEY_ID=$KEY_ID, \ + APIM_TOKEN_URL=$MOCK_URL/apim/oauth2/token, \ + PDM_BUNDLE_URL=$MOCK_URL/apim/check_auth, \ + MNS_EVENT_URL=$MOCK_URL/mns, \ + CLIENT_TIMEOUT=$CLIENT_TIMEOUT, \ + JWKS_SECRET_NAME=$JWKS_SECRET}" || true + wait_for_lambda_ready + aws lambda update-function-code --function-name "$FN" \ + --zip-file "fileb://artifact.zip" \ + --publish + else + aws lambda create-function --function-name "$FN" \ + --runtime "${{ env.LAMBDA_RUNTIME }}" \ + --handler "${{ env.LAMBDA_HANDLER }}" \ + --zip-file "fileb://artifact.zip" \ + --role "${{ steps.role-select.outputs.lambda_role }}" \ + --memory-size 512 \ + --timeout 30 \ + --environment "Variables={APIM_TOKEN_EXPIRY_THRESHOLD=$EXPIRY_THRESHOLD, \ + APIM_PRIVATE_KEY_NAME=$PRIVATE_KEY, \ + APIM_API_KEY_NAME=$API_KEY, \ + APIM_KEY_ID=$KEY_ID, \ + APIM_MTLS_CERT_NAME=$MTLS_CERT, \ + APIM_MTLS_KEY_NAME=$MTLS_KEY, \ + APIM_TOKEN_URL=$MOCK_URL/apim/oauth2/token, \ + PDM_BUNDLE_URL=$MOCK_URL/apim/check_auth, \ + MNS_EVENT_URL=$MOCK_URL/mns, \ + CLIENT_TIMEOUT=$CLIENT_TIMEOUT, \ + JWKS_SECRET_NAME=$JWKS_SECRET}" \ + --publish + wait_for_lambda_ready + fi + + - name: Output function name with mock + run: | + echo "function = ${{ steps.names.outputs.function_name }}" + echo "url = ${{ steps.names.outputs.int_url }}" + + # ---------- Wait on AWS tasks and notify ---------- + - name: Get mTLS certs for testing + id: mtls-certs + uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 + with: + secret-ids: | + /cds/pathology/int/mtls/client1-key-secret + /cds/pathology/int/mtls/client1-key-public + name-transformation: lowercase + + - name: Smoke test preview URL + id: smoke-test + env: + INT_URL: ${{ steps.names.outputs.int_url }} + run: | + if [ -z "$INT_URL" ] || [ "$INT_URL" = "null" ]; then + echo "Integration URL missing" + echo "http_status=missing" >> "$GITHUB_OUTPUT" + echo "http_result=missing-url" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Reachability check: allow 404 (app routes might not exist yet) but fail otherwise + printf '%s' "$_cds_pathology_int_mtls_client1_key_secret" > /tmp/client1-key.pem + printf '%s' "$_cds_pathology_int_mtls_client1_key_public" > /tmp/client1-cert.pem + STATUS=$(curl \ + --cert /tmp/client1-cert.pem \ + --key /tmp/client1-key.pem \ + --silent \ + --output /tmp/preview.headers \ + --write-out '%{http_code}' \ + --head \ + --max-time 30 \ + -X GET "$INT_URL"/_status || true) + rm -f /tmp/client1-key.pem + rm -f /tmp/client1-cert.pem + + if [ "$STATUS" = "404" ]; then + echo "Integration responded with expected 404" + echo "http_status=404" >> "$GITHUB_OUTPUT" + echo "http_result=allowed-404" >> "$GITHUB_OUTPUT" + exit 0 + fi + + if [[ "$STATUS" =~ ^[0-9]{3}$ ]] && [ "$STATUS" -ge 200 ] && [ "$STATUS" -lt 400 ]; then + echo "Integration responded with status $STATUS" + echo "http_status=$STATUS" >> "$GITHUB_OUTPUT" + echo "http_result=success" >> "$GITHUB_OUTPUT" + exit 0 + fi + + echo "Preview responded with unexpected status $STATUS" + if [ -f /tmp/preview.headers ]; then + echo "Response headers:" + cat /tmp/preview.headers + fi + echo "http_status=$STATUS" >> "$GITHUB_OUTPUT" + echo "http_result=unexpected-status" >> "$GITHUB_OUTPUT" + exit 0 + + - name: Get proxygen machine user details + id: proxygen-machine-user + uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 + with: + secret-ids: /cds/pathology/int/proxygen/proxygen-key-secret + name-transformation: lowercase + + - name: Deploy preview API proxy + uses: ./.github/actions/proxy/deploy-proxy + with: + mtls-secret-name: ${{ env.MTLS_SECRET_NAME }} + target-url: ${{ steps.names.outputs.int_url }} + proxy-base-path: "${{ env.PROXYGEN_API_NAME }}-integration" + proxygen-key-secret: ${{ env._cds_pathology_int_proxygen_proxygen_key_secret }} + proxygen-key-id: ${{ env.PROXYGEN_KEY_ID }} + proxygen-client-id: ${{ env.PROXYGEN_CLIENT_ID }} + proxygen-api-name: ${{ env.PROXYGEN_API_NAME }} + + - name: Retrieve Apigee Token + id: apigee-token + shell: bash + run: | + set -euo pipefail + + APIGEE_TOKEN="$(proxygen pytest-nhsd-apim get-token | jq -r '.pytest_nhsd_apim_token' 2>/dev/null)" + if [ -z "$APIGEE_TOKEN" ] || [ "$APIGEE_TOKEN" = "null" ]; then + echo "::error::Failed to retrieve Apigee token" + exit 1 + fi + + echo "::add-mask::$APIGEE_TOKEN" + printf 'apigee-access-token=%s\n' "$APIGEE_TOKEN" >> "$GITHUB_OUTPUT" + echo "Token retrieved successfully (length: ${#APIGEE_TOKEN})" + + - name: "Create coverage artefact name" + id: create-name + uses: ./.github/actions/create-artefact-name + with: + prefix: coverage + + # ---------- Test suites ---------- + - name: "Run unit tests" + uses: ./.github/actions/run-test-suite + with: + test-type: unit + env: local + + - name: "Run contract tests" + uses: ./.github/actions/run-test-suite + with: + test-type: contract + apigee-access-token: ${{ steps.apigee-token.outputs.apigee-access-token }} + + - name: "Run schema validation tests" + uses: ./.github/actions/run-test-suite + with: + test-type: schema + apigee-access-token: ${{ steps.apigee-token.outputs.apigee-access-token }} + + - name: "Run integration tests" + uses: ./.github/actions/run-test-suite + with: + test-type: integration + apigee-access-token: ${{ steps.apigee-token.outputs.apigee-access-token }} + + - name: "Run acceptance tests" + uses: ./.github/actions/run-test-suite + with: + test-type: acceptance + apigee-access-token: ${{ steps.apigee-token.outputs.apigee-access-token }} + + # ---------- Coverage & reporting ---------- + - name: "Download all test coverage artefacts" + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + path: pathology-api/test-artefacts/ + merge-multiple: false + - name: "Download mock test coverage artefacts" + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + path: mocks/test-artefacts/ + merge-multiple: false + - name: "Merge coverage data" + run: make test-coverage + - name: "Rename coverage XML with unique name" + run: | + cd pathology-api/test-artefacts + mv coverage-merged.xml "${{ steps.create-name.outputs.artefact-name }}.xml" + cd ../.. + cd mocks/test-artefacts + mv coverage-merged.xml ${{ steps.create-name.outputs.artefact-name }}-mocks.xml + - name: "Upload combined coverage report" + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: ${{ steps.create-name.outputs.artefact-name }} + path: pathology-api/test-artefacts + retention-days: 30 + - name: "Upload mocks coverage report" + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: ${{ steps.create-name.outputs.artefact-name }}-mocks + path: mocks/test-artefacts + retention-days: 30 + - name: "Download merged coverage report" + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ steps.create-name.outputs.artefact-name }} + path: coverage-reports/ + - name: "Download mock coverage report" + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ steps.create-name.outputs.artefact-name }}-mocks + path: coverage-reports/ + - name: "SonarCloud Scan" + uses: SonarSource/sonarqube-scan-action@299e4b793aaa83bf2aba7c9c14bedbb485688ec4 #7.1.0 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + with: + args: > + -Dsonar.organization=${{ vars.SONAR_ORGANISATION_KEY }} + -Dsonar.projectKey=${{ vars.SONAR_PROJECT_KEY }} + -Dsonar.python.coverage.reportPaths=coverage-reports/${{ steps.create-name.outputs.artefact-name }}.xml,coverage-reports/${{ steps.create-name.outputs.artefact-name }}-mocks.xml + + # ---------- Perform vuln scan and notify ---------- + # - name: Filesystem vuln scan + # - name: SBOM generation diff --git a/.github/workflows/preview-env.yaml b/.github/workflows/preview-env.yaml index d29ab8f0..ca21e575 100644 --- a/.github/workflows/preview-env.yaml +++ b/.github/workflows/preview-env.yaml @@ -31,6 +31,7 @@ env: ENV: "remote" PR_NUMBER: ${{ github.event.pull_request.number }} HOST: "internal-dev.api.service.nhs.uk" + PROXY_ENV: "internal-dev" jobs: pr-preview: @@ -67,8 +68,9 @@ jobs: DEPENDABOT_LAMBDA_ROLE_ARN: ${{ secrets.DEPENDABOT_LAMBDA_ROLE_ARN }} AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }} LAMBDA_ROLE_ARN: ${{ secrets.LAMBDA_ROLE_ARN }} + GITHUB_ACTOR: ${{ github.actor }} run: | - if [ "${{ github.actor }}" = "dependabot[bot]" ]; then + if [ "$GITHUB_ACTOR" = "dependabot[bot]" ]; then echo "aws_role=$DEPENDABOT_AWS_ROLE_ARN" >> "$GITHUB_OUTPUT" echo "lambda_role=$DEPENDABOT_LAMBDA_ROLE_ARN" >> "$GITHUB_OUTPUT" else @@ -86,11 +88,13 @@ jobs: id: branch env: RAW_BRANCH_NAME: "${{ github.head_ref }}" + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_ACTOR: ${{ github.actor }} run: | branch=$RAW_BRANCH_NAME - if [ -z "$branch" ]; then branch="${{ github.ref_name }}"; fi + if [ -z "$branch" ]; then branch="$GITHUB_REF_NAME"; fi - if [ "${{ github.actor }}" = "dependabot[bot]" ]; then + if [ "$GITHUB_ACTOR" = "dependabot[bot]" ]; then safe="dependabot-${{ github.event.pull_request.number }}" else safe=$(echo "$branch" | sed -E 's/[^a-zA-Z0-9._-]+/-/g' | tr '[:upper:]' '[:lower:]') @@ -102,10 +106,10 @@ jobs: - name: Compute function name id: names run: | - SAFE=${{ steps.branch.outputs.safe }} - PREFIX=${{ env.PREVIEW_PREFIX }} - MOCK_PREFIX=${{ env.MOCK_PREFIX }} - INT_PREFIX=${{ env.PREVIEW_INT_PREFIX }} + SAFE="${{ steps.branch.outputs.safe }}" + PREFIX="${{ env.PREVIEW_PREFIX }}" + MOCK_PREFIX="${{ env.MOCK_PREFIX }}" + INT_PREFIX="${{ env.PREVIEW_INT_PREFIX }}" MAX_FN_LEN=62 MAX_PREFIX_LEN=${#PREFIX} if [ ${#MOCK_PREFIX} -gt "$MAX_PREFIX_LEN" ]; then @@ -589,6 +593,7 @@ jobs: proxygen-key-id: ${{ env.PROXYGEN_KEY_ID }} proxygen-client-id: ${{ env.PROXYGEN_CLIENT_ID }} proxygen-api-name: ${{ env.PROXYGEN_API_NAME }} + proxygen-environment: ${{ env.PROXY_ENV}} - name: Deploy int preview API proxy if: github.event.action != 'closed' && github.event.pull_request.user.login != 'dependabot[bot]' @@ -601,6 +606,7 @@ jobs: proxygen-key-id: ${{ env.PROXYGEN_KEY_ID }} proxygen-client-id: ${{ env.PROXYGEN_CLIENT_ID }} proxygen-api-name: ${{ env.PROXYGEN_API_NAME }} + proxygen-environment: ${{ env.PROXY_ENV}} - name: Tear down preview API proxy if: github.event.action == 'closed' @@ -611,6 +617,7 @@ jobs: proxygen-key-id: ${{ env.PROXYGEN_KEY_ID }} proxygen-client-id: ${{ env.PROXYGEN_CLIENT_ID }} proxygen-api-name: ${{ env.PROXYGEN_API_NAME }} + proxygen-environment: ${{ env.PROXY_ENV}} - name: Tear down int preview API proxy if: github.event.action == 'closed' && github.event.pull_request.user.login != 'dependabot[bot]' @@ -621,6 +628,7 @@ jobs: proxygen-key-id: ${{ env.PROXYGEN_KEY_ID }} proxygen-client-id: ${{ env.PROXYGEN_CLIENT_ID }} proxygen-api-name: ${{ env.PROXYGEN_API_NAME }} + proxygen-environment: ${{ env.PROXY_ENV}} - name: Retrieve Apigee Token id: apigee-token diff --git a/.tool-versions b/.tool-versions index 052bb56c..f2371666 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,7 +1,7 @@ # This file is for you! Please, updated to the versions agreed by your team. -pre-commit 3.6.0 -gitleaks 8.18.4 +pre-commit 4.5.1 +gitleaks 8.30.1 # ============================================================================== # The section below is reserved for Docker image versions. diff --git a/bruno/APIM/Get_Auth_Token.bru b/bruno/APIM/Get_Auth_Token.bru index 74257faf..bc80a744 100644 --- a/bruno/APIM/Get_Auth_Token.bru +++ b/bruno/APIM/Get_Auth_Token.bru @@ -20,19 +20,17 @@ script:pre-request { const jwt = require("jsonwebtoken"); const fs = require("node:fs"); const crypto = require("node:crypto"); - const secret = bru.getEnvVar("JWT_SECRET"); const privateKeyPath = bru.getEnvVar("PRIVATE_KEY_PATH"); - if (!secret) { throw new Error("JWT_SECRET environment variable is missing."); } + if (!privateKeyPath) { throw new Error("PRIVATE_KEY_PATH environment variable is missing."); } const privateKey = fs.readFileSync(privateKeyPath); - const payload = { sub: secret, iss: secret, @@ -45,19 +43,14 @@ script:pre-request { algorithm: 'RS512', header: { kid: kid } }; - const token = jwt.sign(payload, privateKey, options); - let new_body = req.getBody(); new_body.push({ name: "client_assertion", value: token }); - req.setBody(new_body); } - const environment = bru.getGlobalEnvVar("APIM_ENV") generateAuthToken(bru, req, `https://${environment}.api.service.nhs.uk/oauth2/token`, bru.getEnvVar("KID")); } - script:post-response { bru.setGlobalEnvVar("auth_token", res.getBody().access_token) } diff --git a/bruno/APIM/Post_Document_Bundle_via_APIM_INT.bru b/bruno/APIM/Post_Document_Bundle_via_APIM_INT.bru index 2d24c9be..61a5c528 100644 --- a/bruno/APIM/Post_Document_Bundle_via_APIM_INT.bru +++ b/bruno/APIM/Post_Document_Bundle_via_APIM_INT.bru @@ -1,7 +1,7 @@ meta { name: Post Document Bundle via APIM - INT type: http - seq: 4 + seq: 3 } post { diff --git a/bruno/APIM/Test_MNS_Pathology_Api_Unable_To_Authenticate.bru b/bruno/APIM/Test_MNS_Pathology_Api_Unable_To_Authenticate.bru new file mode 100644 index 00000000..7d68562b --- /dev/null +++ b/bruno/APIM/Test_MNS_Pathology_Api_Unable_To_Authenticate.bru @@ -0,0 +1,84 @@ +meta { + name: Test_MNS_Pathology_Api_Unable_To_Authenticate + type: http + seq: 5 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "MNS_AUTHENTICATION_ERROR" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 500 + res.body.issue[0].diagnostics: eq "Failed to publish an event" +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_MNS_Pathology_Api_Unable_To_Authorize_Event.bru b/bruno/APIM/Test_MNS_Pathology_Api_Unable_To_Authorize_Event.bru new file mode 100644 index 00000000..35730ee9 --- /dev/null +++ b/bruno/APIM/Test_MNS_Pathology_Api_Unable_To_Authorize_Event.bru @@ -0,0 +1,84 @@ +meta { + name: Test_MNS_Pathology_Api_Unable_To_Authorize_Event + type: http + seq: 5 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "MNS_AUTHORIZATION_ERROR" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 500 + res.body.issue[0].diagnostics: eq "Failed to publish an event" +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_MNS_Service_Experience_Bad_Gateway_Error.bru b/bruno/APIM/Test_MNS_Service_Experience_Bad_Gateway_Error.bru new file mode 100644 index 00000000..99ed5495 --- /dev/null +++ b/bruno/APIM/Test_MNS_Service_Experience_Bad_Gateway_Error.bru @@ -0,0 +1,84 @@ +meta { + name: Test_MNS_Service_Experience_Bad_Gateway_Error + type: http + seq: 7 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "MNS_BAD_GATEWAY_ERROR" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 500 + res.body.issue[0].diagnostics: eq "Failed to publish an event" +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_MNS_Service_Experience_Gateway_Timeout_Error.bru b/bruno/APIM/Test_MNS_Service_Experience_Gateway_Timeout_Error.bru new file mode 100644 index 00000000..b278d6c3 --- /dev/null +++ b/bruno/APIM/Test_MNS_Service_Experience_Gateway_Timeout_Error.bru @@ -0,0 +1,84 @@ +meta { + name: Test_MNS_Service_Experience_Gateway_Timeout_Error + type: http + seq: 8 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "MNS_GATEWAY_TIMEOUT_ERROR" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 500 + res.body.issue[0].diagnostics: eq "Failed to publish an event" +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_MNS_Service_Experience_Validation_Error.bru b/bruno/APIM/Test_MNS_Service_Experience_Validation_Error.bru new file mode 100644 index 00000000..9df7519a --- /dev/null +++ b/bruno/APIM/Test_MNS_Service_Experience_Validation_Error.bru @@ -0,0 +1,84 @@ +meta { + name: Test_MNS_Service_Experience_Validation_Error + type: http + seq: 9 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "MNS_VALIDATION_ERROR" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 500 + res.body.issue[0].diagnostics: eq "Failed to publish an event" +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_MNS_Service_Returns_Client_Side_Error.bru b/bruno/APIM/Test_MNS_Service_Returns_Client_Side_Error.bru new file mode 100644 index 00000000..4f8e9a74 --- /dev/null +++ b/bruno/APIM/Test_MNS_Service_Returns_Client_Side_Error.bru @@ -0,0 +1,84 @@ +meta { + name: Test_MNS_Service_Returns_Client_Side_Error + type: http + seq: 6 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "MNS_SERVER_ERROR" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 500 + res.body.issue[0].diagnostics: eq "Failed to publish an event" +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_PDM_Api_Server_Error.bru b/bruno/APIM/Test_PDM_Api_Server_Error.bru new file mode 100644 index 00000000..731a50fd --- /dev/null +++ b/bruno/APIM/Test_PDM_Api_Server_Error.bru @@ -0,0 +1,96 @@ +meta { + name: Test_PDM_Api_Server_Error + type: http + seq: 12 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "patient", + "resource": { + "resourceType": "Patient", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "PDM_SERVER_ERROR" + } + ] + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 500 + res.body.issue[0].diagnostics: contains Failed to send document: +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_PDM_Api_Validation_Error.bru b/bruno/APIM/Test_PDM_Api_Validation_Error.bru new file mode 100644 index 00000000..f6901469 --- /dev/null +++ b/bruno/APIM/Test_PDM_Api_Validation_Error.bru @@ -0,0 +1,96 @@ +meta { + name: Test_PDM_Api_Validation_Error + type: http + seq: 10 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "patient", + "resource": { + "resourceType": "Patient", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "PDM_VALIDATION_ERROR" + } + ] + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 500 + res.body.issue[0].diagnostics: contains Failed to send document: +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_PDM_Bundle_Succesful_Response.bru b/bruno/APIM/Test_PDM_Bundle_Succesful_Response.bru new file mode 100644 index 00000000..502810ac --- /dev/null +++ b/bruno/APIM/Test_PDM_Bundle_Succesful_Response.bru @@ -0,0 +1,95 @@ +meta { + name: Test_PDM_Bundle_Succesful_Response + type: http + seq: 12 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "patient", + "resource": { + "resourceType": "Patient", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9727710638" + } + ] + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 200 +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_With_Incorrect_ReferenceType.bru b/bruno/APIM/Test_With_Incorrect_ReferenceType.bru new file mode 100644 index 00000000..a370aad4 --- /dev/null +++ b/bruno/APIM/Test_With_Incorrect_ReferenceType.bru @@ -0,0 +1,84 @@ +meta { + name: Test_With_Incorrect_ReferenceType + type: http + seq: 13 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": 123 + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq ('entry', 0, 'resource', 'extension', 0, 'valueReference', 'reference') - Input should be a valid string \n +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_With_Incorrect_ReferenceType_in_Extension.bru b/bruno/APIM/Test_With_Incorrect_ReferenceType_in_Extension.bru new file mode 100644 index 00000000..2b643673 --- /dev/null +++ b/bruno/APIM/Test_With_Incorrect_ReferenceType_in_Extension.bru @@ -0,0 +1,84 @@ +meta { + name: Test_With_Incorrect_ReferenceType_in_Extension + type: http + seq: 12 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest123" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq ServiceRequest resource not found with provided reference. Provided reference: servicerequest123 +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_With_Invalid_Identifiers_in_Organization.bru b/bruno/APIM/Test_With_Invalid_Identifiers_in_Organization.bru new file mode 100644 index 00000000..0a9e3cfb --- /dev/null +++ b/bruno/APIM/Test_With_Invalid_Identifiers_in_Organization.bru @@ -0,0 +1,84 @@ +meta { + name: Test_With_Invalid_Identifiers_in_Organization + type: http + seq: 23 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "http://fhir.nhs.uk/Id/ods-organization-code", + "value": "testorg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Organization (organization) does not define a supported identifier. Supported system 'https://fhir.nhs.uk/Id/ods-organization-code' +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_With_Multiple_Bundle_Entries_With_Same_URL.bru b/bruno/APIM/Test_With_Multiple_Bundle_Entries_With_Same_URL.bru new file mode 100644 index 00000000..ad21c0ab --- /dev/null +++ b/bruno/APIM/Test_With_Multiple_Bundle_Entries_With_Same_URL.bru @@ -0,0 +1,105 @@ +meta { + name: Test_With_Multiple_Bundle_Entries_With_Same_URL + type: http + seq: 26 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Multiple resources provided with same fullUrl: practitionerrole +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_With_Multiple_Identifiers_For_An_Organisation.bru b/bruno/APIM/Test_With_Multiple_Identifiers_For_An_Organisation.bru new file mode 100644 index 00000000..576acdd1 --- /dev/null +++ b/bruno/APIM/Test_With_Multiple_Identifiers_For_An_Organisation.bru @@ -0,0 +1,88 @@ +meta { + name: Test_With_Multiple_Identifiers_For_An_Organisation + type: http + seq: 25 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + }, + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "secondOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Organization (organization) defines multiple identifier values. Identifier values: ['testOrg', 'secondOrg'] +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_Composition.bru b/bruno/APIM/Test_Without_Composition.bru new file mode 100644 index 00000000..2092ae55 --- /dev/null +++ b/bruno/APIM/Test_Without_Composition.bru @@ -0,0 +1,64 @@ +meta { + name: Test_Without_Composition + type: http + seq: 7 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Document must include a single Composition resource +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_Extension_URL_is_incorrect.bru b/bruno/APIM/Test_Without_Extension_URL_is_incorrect.bru new file mode 100644 index 00000000..89b771fa --- /dev/null +++ b/bruno/APIM/Test_Without_Extension_URL_is_incorrect.bru @@ -0,0 +1,84 @@ +meta { + name: Test_Without_Extension_URL_is_incorrect + type: http + seq: 10 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "https://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Composition does not define a valid basedOn-order-or-requisition extension +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_Extension_in_Composition.bru b/bruno/APIM/Test_Without_Extension_in_Composition.bru new file mode 100644 index 00000000..522b920e --- /dev/null +++ b/bruno/APIM/Test_Without_Extension_in_Composition.bru @@ -0,0 +1,76 @@ +meta { + name: Test_Without_Extension_in_Composition + type: http + seq: 8 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Composition does not define a valid basedOn-order-or-requisition extension +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_Organization.bru b/bruno/APIM/Test_Without_Organization.bru new file mode 100644 index 00000000..281ebdc0 --- /dev/null +++ b/bruno/APIM/Test_Without_Organization.bru @@ -0,0 +1,72 @@ +meta { + name: Test_Without_Organization + type: http + seq: 6 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Document must include an Organization resource +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_Organization_Identifier.bru b/bruno/APIM/Test_Without_Organization_Identifier.bru new file mode 100644 index 00000000..1fefdf2b --- /dev/null +++ b/bruno/APIM/Test_Without_Organization_Identifier.bru @@ -0,0 +1,78 @@ +meta { + name: Test_Without_Organization_Identifier + type: http + seq: 17 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization" + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Organisation (organization) does not define a valid subject identifier +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_Organization_Identifier_Value.bru b/bruno/APIM/Test_Without_Organization_Identifier_Value.bru new file mode 100644 index 00000000..d659c0a5 --- /dev/null +++ b/bruno/APIM/Test_Without_Organization_Identifier_Value.bru @@ -0,0 +1,83 @@ +meta { + name: Test_Without_Organization_Identifier_Value + type: http + seq: 20 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq ('entry', 3, 'resource', 'identifier', 0, 'value') - Field required \n +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_Organization_Invalid_System.bru b/bruno/APIM/Test_Without_Organization_Invalid_System.bru new file mode 100644 index 00000000..4c8f2dc1 --- /dev/null +++ b/bruno/APIM/Test_Without_Organization_Invalid_System.bru @@ -0,0 +1,84 @@ +meta { + name: Test_Without_Organization_Invalid_System + type: http + seq: 21 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "http://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Organization (organization) does not define a supported identifier. Supported system 'https://fhir.nhs.uk/Id/ods-organization-code' +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_Organization_Invalid_Value.bru b/bruno/APIM/Test_Without_Organization_Invalid_Value.bru new file mode 100644 index 00000000..8b79c683 --- /dev/null +++ b/bruno/APIM/Test_Without_Organization_Invalid_Value.bru @@ -0,0 +1,84 @@ +meta { + name: Test_Without_Organization_Invalid_Value + type: http + seq: 22 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": 123 + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq ('entry', 3, 'resource', 'identifier', 0, 'value') - Input should be a valid string \n +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_Organization_System.bru b/bruno/APIM/Test_Without_Organization_System.bru new file mode 100644 index 00000000..6acd7fac --- /dev/null +++ b/bruno/APIM/Test_Without_Organization_System.bru @@ -0,0 +1,78 @@ +meta { + name: Test_Without_Organization_System + type: http + seq: 19 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization" + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Organisation (organization) does not define a valid subject identifier +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_PractionerRole.bru b/bruno/APIM/Test_Without_PractionerRole.bru new file mode 100644 index 00000000..c96c8810 --- /dev/null +++ b/bruno/APIM/Test_Without_PractionerRole.bru @@ -0,0 +1,75 @@ +meta { + name: Test_Without_PractionerRole + type: http + seq: 5 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Document must include a PractitionerRole resource +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_PractionerRole_On_ServiceRequest_Requester_Reference.bru b/bruno/APIM/Test_Without_PractionerRole_On_ServiceRequest_Requester_Reference.bru new file mode 100644 index 00000000..086a4118 --- /dev/null +++ b/bruno/APIM/Test_Without_PractionerRole_On_ServiceRequest_Requester_Reference.bru @@ -0,0 +1,84 @@ +meta { + name: Test_Without_PractionerRole_On_ServiceRequest_Requester_Reference + type: http + seq: 24 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "Testrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq ServiceRequest does not define a valid requester +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_PractionerRole_Reference.bru b/bruno/APIM/Test_Without_PractionerRole_Reference.bru new file mode 100644 index 00000000..cae9d249 --- /dev/null +++ b/bruno/APIM/Test_Without_PractionerRole_Reference.bru @@ -0,0 +1,84 @@ +meta { + name: Test_Without_PractionerRole_Reference + type: http + seq: 16 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq "Organization resource not found with provided reference. Provided reference: " +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_PractionerRole_Reference_Value.bru b/bruno/APIM/Test_Without_PractionerRole_Reference_Value.bru new file mode 100644 index 00000000..e25e7582 --- /dev/null +++ b/bruno/APIM/Test_Without_PractionerRole_Reference_Value.bru @@ -0,0 +1,83 @@ +meta { + name: Test_Without_PractionerRole_Reference_Value + type: http + seq: 17 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq ('entry', 2, 'resource', 'organization', 'reference') - Field required \n +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_Reference_in_Extension.bru b/bruno/APIM/Test_Without_Reference_in_Extension.bru new file mode 100644 index 00000000..df627216 --- /dev/null +++ b/bruno/APIM/Test_Without_Reference_in_Extension.bru @@ -0,0 +1,76 @@ +meta { + name: Test_Without_Reference_in_Extension + type: http + seq: 11 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Composition does not define a valid basedOn-order-or-requisition extension +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_ServiceRequest.bru b/bruno/APIM/Test_Without_ServiceRequest.bru new file mode 100644 index 00000000..9d1a6e78 --- /dev/null +++ b/bruno/APIM/Test_Without_ServiceRequest.bru @@ -0,0 +1,75 @@ +meta { + name: Test_Without_ServiceRequest + type: http + seq: 4 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Document must include a ServiceRequest resource +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_ServiceRequest_Requester.bru b/bruno/APIM/Test_Without_ServiceRequest_Requester.bru new file mode 100644 index 00000000..4a2c38a2 --- /dev/null +++ b/bruno/APIM/Test_Without_ServiceRequest_Requester.bru @@ -0,0 +1,81 @@ +meta { + name: Test_Without_ServiceRequest_Requester + type: http + seq: 14 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest" + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq ServiceRequest does not define a valid requester +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_ServiceRequest_Requester_Reference.bru b/bruno/APIM/Test_Without_ServiceRequest_Requester_Reference.bru new file mode 100644 index 00000000..8dbdbe63 --- /dev/null +++ b/bruno/APIM/Test_Without_ServiceRequest_Requester_Reference.bru @@ -0,0 +1,81 @@ +meta { + name: Test_Without_ServiceRequest_Requester_Reference + type: http + seq: 15 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest" + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq ServiceRequest does not define a valid requester +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_Without_ServiceRequest_Resource.bru b/bruno/APIM/Test_Without_ServiceRequest_Resource.bru new file mode 100644 index 00000000..fa078ab4 --- /dev/null +++ b/bruno/APIM/Test_Without_ServiceRequest_Resource.bru @@ -0,0 +1,75 @@ +meta { + name: Test_Without_ServiceRequest_Resource + type: http + seq: 8 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "test-nhs-number" + } + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + }, + { + "fullUrl": "organization", + "resource": { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "testOrg" + } + ] + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Document must include a ServiceRequest resource +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/environments/APIM.bru b/bruno/APIM/environments/APIM.bru index 7e5d0a67..e1914bac 100644 --- a/bruno/APIM/environments/APIM.bru +++ b/bruno/APIM/environments/APIM.bru @@ -1,6 +1,6 @@ vars:secret [ + PR_NUMBER, PRIVATE_KEY_PATH, JWT_SECRET, - PR_NUMBER, KID ] diff --git a/bruno/PDM/Bundle/Post_a_Transaction_Bundle.bru b/bruno/PDM/Bundle/Post_a_Transaction_Bundle.bru index 1f289b16..899b5eeb 100644 --- a/bruno/PDM/Bundle/Post_a_Transaction_Bundle.bru +++ b/bruno/PDM/Bundle/Post_a_Transaction_Bundle.bru @@ -1,7 +1,7 @@ meta { name: Post a Transaction Bundle type: http - seq: 5 + seq: 2 } post { diff --git a/bruno/PDM/environments/PDM.bru b/bruno/PDM/environments/PDM.bru new file mode 100644 index 00000000..7e5d0a67 --- /dev/null +++ b/bruno/PDM/environments/PDM.bru @@ -0,0 +1,6 @@ +vars:secret [ + PRIVATE_KEY_PATH, + JWT_SECRET, + PR_NUMBER, + KID +] diff --git a/infrastructure/images/build-container/Dockerfile b/infrastructure/images/build-container/Dockerfile index 97871fc1..afbb6ac8 100644 --- a/infrastructure/images/build-container/Dockerfile +++ b/infrastructure/images/build-container/Dockerfile @@ -1,9 +1,10 @@ -FROM mcr.microsoft.com/vscode/devcontainers/base:alpine-3.22 AS pathology-build-container +FROM mcr.microsoft.com/devcontainers/base:alpine3.23 AS pathology-build-container ENV PYTHON_VERSION="3.14" -ENV ASDF_DOWNLOAD_URL="https://github.com/asdf-vm/asdf/releases/download/v0.18.0" -ENV EDITORCONFIG_DOWNLOAD_URL="https://github.com/editorconfig-checker/editorconfig-checker/releases/download/v3.4.1" +ENV ASDF_DOWNLOAD_URL="https://github.com/asdf-vm/asdf/releases/download/v0.18.1" +ENV EDITORCONFIG_DOWNLOAD_URL="https://github.com/editorconfig-checker/editorconfig-checker/releases/download/v3.6.1" + ARG INCLUDE_DEV_CERTS ARG DEV_CERT_FILENAME @@ -87,10 +88,10 @@ WORKDIR /asdf # If we're running on an arm64 architecture download the arm64 executeable. RUN if [ "$(uname -m)" = "aarch64" ] ; then \ echo "Installing ARM asdf executable..." ; \ - wget -O asdf.tar.gz "$ASDF_DOWNLOAD_URL/asdf-v0.18.0-linux-arm64.tar.gz"; \ + wget -O asdf.tar.gz "$ASDF_DOWNLOAD_URL/asdf-v0.18.1-linux-arm64.tar.gz"; \ else \ echo "Installing x86 asdf executable..." ; \ - wget -O asdf.tar.gz "$ASDF_DOWNLOAD_URL/asdf-v0.18.0-linux-amd64.tar.gz"; \ + wget -O asdf.tar.gz "$ASDF_DOWNLOAD_URL/asdf-v0.18.1-linux-amd64.tar.gz"; \ fi \ && tar -xvf asdf.tar.gz \