Skip to content

Commit 84ef272

Browse files
[CDAPI-100]: Run remote tests as part of CI
1 parent 2d7d98d commit 84ef272

File tree

6 files changed

+283
-8
lines changed

6 files changed

+283
-8
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Generate Apigee Token
2+
description: Generate the Apigee Token needed to run the tests
3+
4+
inputs:
5+
proxygen-key-secret:
6+
description: 'Proxygen private key secret'
7+
required: true
8+
proxygen-key-id:
9+
description: 'Proxygen key ID'
10+
required: true
11+
proxygen-client-id:
12+
description: 'Proxygen client ID'
13+
required: true
14+
proxygen-api-name:
15+
description: 'Proxygen API name'
16+
required: true
17+
outputs:
18+
apigee-access-token:
19+
description: "The token needed to use apigee in our testing"
20+
value: ${{ steps.retrieve_apigee_token.outputs.apigee-access-token }}
21+
22+
runs:
23+
using: composite
24+
steps:
25+
- name: Configure Proxygen
26+
uses: ./.github/actions/proxy/configure-proxygen
27+
with:
28+
proxygen-key-secret: ${{ inputs.proxygen-key-secret }}
29+
proxygen-key-id: ${{ inputs.proxygen-key-id }}
30+
proxygen-client-id: ${{ inputs.proxygen-client-id }}
31+
proxygen-api-name: ${{ inputs.proxygen-api-name }}
32+
33+
- id: retrieve_apigee_token
34+
name: Retrieve token
35+
shell: bash
36+
run: |
37+
TOKEN=$(proxygen pytest-nhsd-apim get-token | jq -r '.pytest_nhsd_apim_token')
38+
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
39+
echo "::error::Failed to retrieve Apigee token"
40+
exit 1
41+
fi
42+
echo "apigee-access-token=$TOKEN" >> $GITHUB_OUTPUT
43+
echo "Token retrieved successfully (length: ${#TOKEN})"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Retrieve Apigee Token from Secrets Manager
2+
description: Configure AWS credentials and retrieve the Apigee token from AWS Secrets Manager
3+
4+
inputs:
5+
secret-name:
6+
description: 'The name of the secret in AWS Secrets Manager'
7+
required: true
8+
aws-role-arn:
9+
description: 'AWS IAM role ARN to assume'
10+
required: true
11+
aws-region:
12+
description: 'AWS region'
13+
required: true
14+
default: 'eu-west-2'
15+
16+
outputs:
17+
apigee-access-token:
18+
description: "The Apigee access token retrieved from Secrets Manager"
19+
value: ${{ steps.set-token.outputs.token }}
20+
21+
runs:
22+
using: composite
23+
steps:
24+
- name: Configure AWS credentials
25+
uses: aws-actions/configure-aws-credentials@a7a2c1125c67f40a1e95768f4e4a7d8f019f87af
26+
with:
27+
role-to-assume: ${{ inputs.aws-role-arn }}
28+
aws-region: ${{ inputs.aws-region }}
29+
30+
- name: Retrieve token from Secrets Manager
31+
uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802
32+
with:
33+
secret-ids: ${{ inputs.secret-name }}
34+
parse-json-secrets: false
35+
36+
- name: Set token output
37+
id: set-token
38+
shell: bash
39+
run: |
40+
SECRET_NAME="${{ inputs.secret-name }}"
41+
# AWS action creates env var with secret name (hyphens→underscores, lowercase→uppercase)
42+
ENV_VAR_NAME=$(echo "$SECRET_NAME" | tr '-' '_' | tr '[:lower:]' '[:upper:]')
43+
TOKEN_VALUE="${!ENV_VAR_NAME}"
44+
if [ -z "$TOKEN_VALUE" ]; then
45+
echo "::error::Failed to retrieve token from Secrets Manager"
46+
exit 1
47+
fi
48+
echo "token=$TOKEN_VALUE" >> $GITHUB_OUTPUT
49+
echo "Token retrieved successfully from Secrets Manager"

.github/actions/setup-python-project/action.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ inputs:
77
runs:
88
using: "composite"
99
steps:
10+
- name: Install system dependencies
11+
shell: bash
12+
run: |
13+
sudo apt-get update
14+
sudo apt-get install -y libxml2-dev libxslt-dev
1015
- name: "Set up Python"
1116
uses: actions/setup-python@v6
1217
with:

.github/workflows/stage-2-test.yaml

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
name: "Test stage"
22

3+
permissions:
4+
id-token: write
5+
contents: read
6+
37
env:
4-
BASE_URL: "http://localhost:5002"
8+
BASE_URL: "https://internal-dev.api.service.nhs.uk/pathology-laboratory-reporting-pr-32"
59
HOST: "localhost"
10+
ENV: "remote"
11+
PR_NUMBER: "32"
12+
AWS_REGION: eu-west-2
13+
PROXYGEN_KEY_ID: ${{ vars.PREVIEW_ENV_PROXYGEN_KEY_ID }}
14+
PROXYGEN_CLIENT_ID: ${{ vars.PREVIEW_ENV_PROXYGEN_CLIENT_ID }}
15+
PROXYGEN_API_NAME: ${{ vars.PROXYGEN_API_NAME }}
616

717
on:
818
workflow_call:
@@ -27,13 +37,97 @@ jobs:
2737
with:
2838
prefix: coverage
2939

40+
generate-apigee-token:
41+
name: "Generate Apigee token"
42+
runs-on: ubuntu-latest
43+
outputs:
44+
secret-name: ${{ steps.store-token.outputs.secret-name }}
45+
steps:
46+
- name: "Checkout code"
47+
uses: actions/checkout@v6
48+
49+
- name: "Set up Python"
50+
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
51+
with:
52+
python-version: ${{ inputs.python_version }}
53+
54+
- name: Select AWS role inputs
55+
id: role-select
56+
env:
57+
DEPENDABOT_AWS_ROLE_ARN: ${{ secrets.DEPENDABOT_AWS_ROLE_ARN }}
58+
DEPENDABOT_LAMBDA_ROLE_ARN: ${{ secrets.DEPENDABOT_LAMBDA_ROLE_ARN }}
59+
AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }}
60+
LAMBDA_ROLE_ARN: ${{ secrets.LAMBDA_ROLE_ARN }}
61+
run: |
62+
if [ "${{ github.actor }}" = "dependabot[bot]" ]; then
63+
echo "aws_role=$DEPENDABOT_AWS_ROLE_ARN" >> "$GITHUB_OUTPUT"
64+
echo "lambda_role=$DEPENDABOT_LAMBDA_ROLE_ARN" >> "$GITHUB_OUTPUT"
65+
else
66+
echo "aws_role=$AWS_ROLE_ARN" >> "$GITHUB_OUTPUT"
67+
echo "lambda_role=$LAMBDA_ROLE_ARN" >> "$GITHUB_OUTPUT"
68+
fi
69+
70+
- name: Configure AWS credentials (OIDC)
71+
uses: aws-actions/configure-aws-credentials@a7a2c1125c67f40a1e95768f4e4a7d8f019f87af
72+
with:
73+
role-to-assume: ${{ steps.role-select.outputs.aws_role }}
74+
aws-region: ${{ env.AWS_REGION }}
75+
76+
- name: Get proxygen machine user details
77+
id: proxygen-machine-user
78+
uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802
79+
with:
80+
secret-ids: /cds/pathology/dev/proxygen/proxygen-key-secret
81+
name-transformation: lowercase
82+
83+
- name: Generate Apigee token
84+
id: generate-token
85+
uses: ./.github/actions/proxy/generate-apigee-token
86+
with:
87+
proxygen-key-secret: ${{ env._cds_pathology_dev_proxygen_proxygen_key_secret }}
88+
proxygen-key-id: ${{ env.PROXYGEN_KEY_ID }}
89+
proxygen-client-id: ${{ env.PROXYGEN_CLIENT_ID }}
90+
proxygen-api-name: ${{ env.PROXYGEN_API_NAME }}
91+
92+
- name: Store token in AWS Secrets Manager
93+
id: store-token
94+
shell: bash
95+
env:
96+
TOKEN: ${{ steps.generate-token.outputs.apigee-access-token }}
97+
run: |
98+
if [ -z "$TOKEN" ]; then
99+
echo "::error::Token is empty"
100+
exit 1
101+
fi
102+
SECRET_NAME="apigee-token-${{ github.run_id }}-${{ github.run_attempt }}"
103+
aws secretsmanager create-secret \
104+
--name "$SECRET_NAME" \
105+
--description "Temporary Apigee token for workflow run ${{ github.run_id }}" \
106+
--secret-string "$TOKEN" \
107+
--region ${{ env.AWS_REGION }}
108+
echo "secret-name=$SECRET_NAME" >> $GITHUB_OUTPUT
109+
echo "Token stored securely in AWS Secrets Manager: $SECRET_NAME"
110+
30111
test-unit:
31112
name: "Unit tests"
32113
runs-on: ubuntu-latest
33114
timeout-minutes: 5
115+
needs: [generate-apigee-token]
116+
env:
117+
ENV: "local"
34118
steps:
35119
- name: "Checkout code"
36120
uses: actions/checkout@v6
121+
- name: Retrieve Apigee token
122+
id: get-token
123+
uses: ./.github/actions/retrieve-apigee-token
124+
with:
125+
secret-name: ${{ needs.generate-apigee-token.outputs.secret-name }}
126+
aws-role-arn: ${{ secrets.AWS_ROLE_ARN }}
127+
aws-region: ${{ env.AWS_REGION }}
128+
- name: Set token environment variable
129+
shell: bash
130+
run: echo "APIGEE_ACCESS_TOKEN=${{ steps.get-token.outputs.apigee-access-token }}" >> $GITHUB_ENV
37131
- name: "Setup Python project"
38132
uses: ./.github/actions/setup-python-project
39133
with:
@@ -57,9 +151,20 @@ jobs:
57151
name: "Contract tests"
58152
runs-on: ubuntu-latest
59153
timeout-minutes: 5
154+
needs: [generate-apigee-token]
60155
steps:
61156
- name: "Checkout code"
62157
uses: actions/checkout@v6
158+
- name: Retrieve Apigee token
159+
id: get-token
160+
uses: ./.github/actions/retrieve-apigee-token
161+
with:
162+
secret-name: ${{ needs.generate-apigee-token.outputs.secret-name }}
163+
aws-role-arn: ${{ secrets.AWS_ROLE_ARN }}
164+
aws-region: ${{ env.AWS_REGION }}
165+
- name: Set token environment variable
166+
shell: bash
167+
run: echo "APIGEE_ACCESS_TOKEN=${{ steps.get-token.outputs.apigee-access-token }}" >> $GITHUB_ENV
63168
- name: "Setup Python project"
64169
uses: ./.github/actions/setup-python-project
65170
with:
@@ -87,9 +192,20 @@ jobs:
87192
name: "Schema validation tests"
88193
runs-on: ubuntu-latest
89194
timeout-minutes: 5
195+
needs: [generate-apigee-token]
90196
steps:
91197
- name: "Checkout code"
92198
uses: actions/checkout@v6
199+
- name: Retrieve Apigee token
200+
id: get-token
201+
uses: ./.github/actions/retrieve-apigee-token
202+
with:
203+
secret-name: ${{ needs.generate-apigee-token.outputs.secret-name }}
204+
aws-role-arn: ${{ secrets.AWS_ROLE_ARN }}
205+
aws-region: ${{ env.AWS_REGION }}
206+
- name: Set token environment variable
207+
shell: bash
208+
run: echo "APIGEE_ACCESS_TOKEN=${{ steps.get-token.outputs.apigee-access-token }}" >> $GITHUB_ENV
93209
- name: "Setup Python project"
94210
uses: ./.github/actions/setup-python-project
95211
with:
@@ -117,9 +233,20 @@ jobs:
117233
name: "Integration tests"
118234
runs-on: ubuntu-latest
119235
timeout-minutes: 10
236+
needs: [generate-apigee-token]
120237
steps:
121238
- name: "Checkout code"
122239
uses: actions/checkout@v6
240+
- name: Retrieve Apigee token
241+
id: get-token
242+
uses: ./.github/actions/retrieve-apigee-token
243+
with:
244+
secret-name: ${{ needs.generate-apigee-token.outputs.secret-name }}
245+
aws-role-arn: ${{ secrets.AWS_ROLE_ARN }}
246+
aws-region: ${{ env.AWS_REGION }}
247+
- name: Set token environment variable
248+
shell: bash
249+
run: echo "APIGEE_ACCESS_TOKEN=${{ steps.get-token.outputs.apigee-access-token }}" >> $GITHUB_ENV
123250
- name: "Setup Python project"
124251
uses: ./.github/actions/setup-python-project
125252
with:
@@ -129,6 +256,7 @@ jobs:
129256
with:
130257
python-version: ${{ inputs.python_version }}
131258
- name: "Run integration test"
259+
shell: bash
132260
run: make test-integration
133261
- name: "Upload integration test results"
134262
if: always()
@@ -147,9 +275,20 @@ jobs:
147275
name: "Acceptance tests"
148276
runs-on: ubuntu-latest
149277
timeout-minutes: 10
278+
needs: [generate-apigee-token]
150279
steps:
151280
- name: "Checkout code"
152281
uses: actions/checkout@v6
282+
- name: Retrieve Apigee token
283+
id: get-token
284+
uses: ./.github/actions/retrieve-apigee-token
285+
with:
286+
secret-name: ${{ needs.generate-apigee-token.outputs.secret-name }}
287+
aws-role-arn: ${{ secrets.AWS_ROLE_ARN }}
288+
aws-region: ${{ env.AWS_REGION }}
289+
- name: Set token environment variable
290+
shell: bash
291+
run: echo "APIGEE_ACCESS_TOKEN=${{ steps.get-token.outputs.apigee-access-token }}" >> $GITHUB_ENV
153292
- name: "Setup Python project"
154293
uses: ./.github/actions/setup-python-project
155294
with:
@@ -230,3 +369,30 @@ jobs:
230369
-Dsonar.organization=${{ vars.SONAR_ORGANISATION_KEY }}
231370
-Dsonar.projectKey=${{ vars.SONAR_PROJECT_KEY }}
232371
-Dsonar.python.coverage.reportPaths=coverage-reports/${{ needs.create-coverage-name.outputs.coverage-name }}.xml
372+
373+
cleanup-apigee-token:
374+
name: "Cleanup Apigee token"
375+
runs-on: ubuntu-latest
376+
needs: [generate-apigee-token, test-unit, test-contract, test-schema, test-integration, test-acceptance]
377+
if: always()
378+
timeout-minutes: 2
379+
steps:
380+
- name: Configure AWS credentials
381+
uses: aws-actions/configure-aws-credentials@a7a2c1125c67f40a1e95768f4e4a7d8f019f87af
382+
with:
383+
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
384+
aws-region: ${{ env.AWS_REGION }}
385+
386+
- name: Delete secret from AWS Secrets Manager
387+
shell: bash
388+
run: |
389+
SECRET_NAME="${{ needs.generate-apigee-token.outputs.secret-name }}"
390+
if [ -n "$SECRET_NAME" ]; then
391+
aws secretsmanager delete-secret \
392+
--secret-id "$SECRET_NAME" \
393+
--force-delete-without-recovery \
394+
--region ${{ env.AWS_REGION }} || true
395+
echo "Secret $SECRET_NAME deleted from Secrets Manager"
396+
else
397+
echo "No secret name provided, skipping cleanup"
398+
fi

.gitleaksignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ cd9c0efec38c5d63053dd865e5d4e207c0760d91:docs/guides/Perform_static_analysis.md:
66

77
pathology-api/pyproject.toml:ipv4:51
88
pathology-api/pyproject.toml:ipv4:50
9+
mocks/pyproject.toml:ipv4:54
10+
mocks/pyproject.toml:ipv4:55

scripts/tests/run-test.sh

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,23 @@ else
4242
COV_PATH="src/pathology_api"
4343
fi
4444

45-
# Note: TEST_PATH is intentionally unquoted to allow glob expansion for unit tests
46-
poetry run pytest ${TEST_PATH} -v \
47-
--cov=${COV_PATH} \
48-
--cov-report=html:test-artefacts/coverage-html \
49-
--cov-report=term \
50-
--junit-xml="test-artefacts/${TEST_TYPE}-tests.xml" \
51-
--html="test-artefacts/${TEST_TYPE}-tests.html" --self-contained-html
45+
if [ "$ENV" = "remote" ]; then
46+
# Note: TEST_PATH is intentionally unquoted to allow glob expansion for unit tests
47+
poetry run pytest ${TEST_PATH} --env="remote" -v \
48+
--api-name=pathology-laboratory-reporting --proxy-name=pathology-laboratory-reporting--internal-dev--pathology-laboratory-reporting-pr-${PR_NUMBER} \
49+
--cov=${COV_PATH} \
50+
--cov-report=html:test-artefacts/coverage-html \
51+
--cov-report=term \
52+
--junit-xml="test-artefacts/${TEST_TYPE}-tests.xml" \
53+
--html="test-artefacts/${TEST_TYPE}-tests.html" --self-contained-html
54+
else
55+
poetry run pytest ${TEST_PATH} -v \
56+
--cov=${COV_PATH} \
57+
--cov-report=html:test-artefacts/coverage-html \
58+
--cov-report=term \
59+
--junit-xml="test-artefacts/${TEST_TYPE}-tests.xml" \
60+
--html="test-artefacts/${TEST_TYPE}-tests.html" --self-contained-html
61+
fi
5262

5363
# Save coverage data file for merging
5464
mv .coverage "test-artefacts/coverage.${TEST_TYPE}"

0 commit comments

Comments
 (0)