Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"omzPlugins": "https://github.com/zsh-users/zsh-autosuggestions.git https://github.com/zsh-users/zsh-syntax-highlighting.git"
}
},
"postCreateCommand": "doas apk add --no-cache openjdk21-jre && scripts/devcontainer/configure-zsh.sh && bash -c 'source ~/.bashrc && make config && pyenv activate pathology && make dependencies'",
"postCreateCommand": "doas apk add --no-cache openjdk21-jre && scripts/devcontainer/configure-zsh.sh && bash -c 'source ~/.bashrc && make config && make dependencies'",
"initializeCommand": "scripts/devcontainer/create-docker-network-if-required.sh && cp .tool-versions ${localWorkspaceFolder}/infrastructure/images/build-container/resources/.tool-versions",
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind,consistency=cached"
Expand Down
45 changes: 29 additions & 16 deletions .github/workflows/preview-env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ env:
PYTHON_VERSION: 3.14
LAMBDA_RUNTIME: python3.14
LAMBDA_HANDLER: lambda_handler.handler
MOCK_LAMBDA_HANDLER: handler.handler
MOCK_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 }}
Expand Down Expand Up @@ -48,18 +48,10 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Package artifact
- name: Package artifacts
run: |
make build

# Place holder mock artifact packaging to allow testing of mock API in preview environment;
# can be extended to build a real mock Lambda if needed
- name: Package mock artifact
run: |
cd infrastructure/environments/preview
rm -f mock_artifact.zip
zip -r mock_artifact.zip .

- name: Select AWS role inputs
id: role-select
env:
Expand Down Expand Up @@ -203,12 +195,23 @@ jobs:
echo "url = ${{ steps.names.outputs.preview_url }}"

# ---------- Handle mock endpoints ----------
- name: Get Secrets for mocks
uses: aws-actions/aws-secretsmanager-get-secrets@a9a7eb4e2f2871d30dc5b892576fde60a2ecc802
with:
secret-ids: |
/cds/pathology/dev/jwks/secret
name-transformation: lowercase

- name: Create or update mock Lambda (on open/sync/reopen)
if: github.event.action != 'closed'
env:
TOKEN_EXPIRY_TIME: ${{ secrets.TOKEN_LIFETIME }}
AUTH_URL: "${{ steps.names.outputs.mock_preview_url }}/apim/oauth2/token"
JWKS_SECRET: ${{ env._cds_pathology_dev_jwks_secret }}
PUBLIC_KEY_URL: "https://example.com"
TOKEN_TABLE_NAME: "mock_services_dev"
run: |
cd infrastructure/environments/preview
cd mocks/target/
MFN="${{ steps.names.outputs.mock_function_name }}"
SAFE="${{ steps.branch.outputs.safe }}"
TOKEN_LIFETIME="${TOKEN_EXPIRY_TIME:-15m}"
Expand All @@ -233,18 +236,28 @@ jobs:
--handler "${{ env.MOCK_LAMBDA_HANDLER }}" \
--environment "Variables={CLIENT_PUBLIC_KEY_ARN=mock, \
DDB_INDEX_TAG=$SAFE, \
TOKEN_LIFETIME=$TOKEN_LIFETIME}" || true
TOKEN_LIFETIME=$TOKEN_LIFETIME, \
AUTH_URL=$AUTH_URL, \
PUBLIC_KEY_URL=$PUBLIC_KEY_URL, \
API_KEY=$JWKS_SECRET, \
TOKEN_TABLE_NAME=$TOKEN_TABLE_NAME \
}" || true
wait_for_lambda_ready
aws lambda update-function-code --function-name "$MFN" --zip-file "fileb://mock_artifact.zip" --publish
aws lambda update-function-code --function-name "$MFN" --zip-file "fileb://artifact.zip" --publish
else
aws lambda create-function --function-name "$MFN" \
--runtime "${{ env.LAMBDA_RUNTIME }}" \
--handler "${{ env.MOCK_LAMBDA_HANDLER }}" \
--zip-file "fileb://mock_artifact.zip" \
--zip-file "fileb://artifact.zip" \
--role "${{ steps.role-select.outputs.lambda_role }}" \
--environment "Variables={CLIENT_PUBLIC_KEY_ARN=mock, \
DDB_INDEX_TAG=$SAFE, \
TOKEN_LIFETIME=$TOKEN_LIFETIME}" \
TOKEN_LIFETIME=$TOKEN_LIFETIME, \
AUTH_URL=$AUTH_URL, \
PUBLIC_KEY_URL=$PUBLIC_KEY_URL, \
API_KEY=$JWKS_SECRET, \
TOKEN_TABLE_NAME=$TOKEN_TABLE_NAME, \
}" \
--publish
wait_for_lambda_ready
fi
Expand Down Expand Up @@ -454,7 +467,7 @@ jobs:
'**Deployment Complete**',
`- Preview URL: [${url}](${url}) — [Status](${url}/_status)`,
` - Smoke Test: ${smokeReadable} (HTTP ${smokeStatus})`,
`- Mock URL: [${mock_url}](${mock_url})`,
`- Mock URL: [${mock_url}](${mock_url}) — [Status](${mock_url}/_status)`,
` - Smoke Mock Test: ${smokeMockReadable} (HTTP ${smokeMockStatus})`,
`- Proxy URL: [${proxy_url}](${proxy_url})`,
`- Lambda Function: ${fn}`,
Expand Down
32 changes: 30 additions & 2 deletions .github/workflows/stage-2-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,20 @@ jobs:
python-version: ${{ inputs.python_version }}
- name: "Run unit test suite"
run: make test-unit
- name: "Upload unit test results"
- name: "Upload unit test results for pathology-api"
if: always()
uses: actions/upload-artifact@v6
with:
name: unit-test-results
path: pathology-api/test-artefacts/
retention-days: 30
- name: "Upload unit test results for mocks"
if: always()
uses: actions/upload-artifact@v6
with:
name: mock-unit-test-results
path: mocks/test-artefacts/
retention-days: 30
- name: "Publish unit test results to summary"
if: always()
uses: test-summary/action@31493c76ec9e7aa675f1585d3ed6f1da69269a86 # v2.4
Expand Down Expand Up @@ -191,19 +198,35 @@ jobs:
with:
path: pathology-api/test-artefacts/
merge-multiple: false
- name: "Download mock test coverage artefacts"
uses: actions/download-artifact@v7
with:
name: mock-unit-test-results
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 ${{ needs.create-coverage-name.outputs.coverage-name }}.xml
cd ../..
cd mocks/test-artefacts
mv coverage-merged.xml ${{ needs.create-coverage-name.outputs.coverage-name }}-mocks.xml
- name: "Upload combined coverage report"
if: always()
uses: actions/upload-artifact@v6
with:
name: ${{ needs.create-coverage-name.outputs.coverage-name }}
path: pathology-api/test-artefacts
retention-days: 30
- name: "Upload mocks coverage report"
if: always()
uses: actions/upload-artifact@v6
with:
name: ${{ needs.create-coverage-name.outputs.coverage-name }}-mocks
path: mocks/test-artefacts
retention-days: 30

sonarcloud-analysis:
name: "SonarCloud Analysis"
Expand All @@ -221,6 +244,11 @@ jobs:
with:
name: ${{ needs.create-coverage-name.outputs.coverage-name }}
path: coverage-reports/
- name: "Download mock coverage report"
uses: actions/download-artifact@v7
with:
name: ${{ needs.create-coverage-name.outputs.coverage-name }}-mocks
path: coverage-reports/
- name: "SonarCloud Scan"
uses: SonarSource/sonarqube-scan-action@v7
env:
Expand All @@ -229,4 +257,4 @@ jobs:
args: >
-Dsonar.organization=${{ vars.SONAR_ORGANISATION_KEY }}
-Dsonar.projectKey=${{ vars.SONAR_PROJECT_KEY }}
-Dsonar.python.coverage.reportPaths=coverage-reports/${{ needs.create-coverage-name.outputs.coverage-name }}.xml
-Dsonar.python.coverage.reportPaths=coverage-reports/${{ needs.create-coverage-name.outputs.coverage-name }}.xml,coverage-reports/${{ needs.create-coverage-name.outputs.coverage-name }}-mocks.xml
1 change: 0 additions & 1 deletion .gitleaksignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ cd9c0efec38c5d63053dd865e5d4e207c0760d91:docs/guides/Perform_static_analysis.md:

pathology-api/pyproject.toml:ipv4:51
pathology-api/pyproject.toml:ipv4:50

mocks/pyproject.toml:ipv4:54
mocks/pyproject.toml:ipv4:55
95 changes: 92 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,41 @@ dockerNetwork := pathology-local
# Example CI/CD targets are: dependencies, build, publish, deploy, clean, etc.

.PHONY: dependencies
.ONESHELL:
dependencies: # Install dependencies needed to build and test the project @Pipeline
if [[ "$${IN_BUILD_CONTAINER}" == "true" ]]; then \
eval "$$(pyenv init -)"; \
pyenv activate pathology; \
fi

cd pathology-api && poetry sync
cd ../

if [[ "$${IN_BUILD_CONTAINER}" == "true" ]]; then \
pyenv deactivate pathology; \
fi

if [[ "$${IN_BUILD_CONTAINER}" == "true" ]]; then \
pyenv activate pathology-mocks; \
fi

cd mocks && poetry sync
cd ../

if [[ "$${IN_BUILD_CONTAINER}" == "true" ]]; then \
pyenv deactivate pathology-mocks; \
fi

.PHONY: build-pathology
.ONESHELL:
build-pathology:
@if [[ "$${IN_BUILD_CONTAINER}" == "true" ]]; then \
eval "$$(pyenv init -)"; \
pyenv activate pathology; \
fi

.PHONY: build
build: clean-artifacts dependencies
@cd pathology-api
@echo "Starting build for pathology API..."
@echo "Running type checks..."
@rm -rf target && rm -rf dist
@poetry run mypy --no-namespace-packages .
Expand All @@ -35,11 +64,51 @@ build: clean-artifacts dependencies
@cd ./target/pathology-api
@zip -r "../artifact.zip" .

@if [[ "$${IN_BUILD_CONTAINER}" == "true" ]]; then \
pyenv deactivate pathology; \
fi

.PHONY: build-mocks
.ONESHELL:
build-mocks:
@if [[ "$${IN_BUILD_CONTAINER}" == "true" ]]; then \
eval "$$(pyenv init -)"; \
pyenv activate pathology-mocks; \
fi

@cd mocks
@echo "Starting build for mocks..."
@echo "Running type checks..."
@rm -rf target && rm -rf dist
@poetry run mypy --no-namespace-packages .
@echo "Packaging dependencies..."
@poetry build --format=wheel
VERSION=$$(poetry version -s)
@pip install "dist/pathology_api_mocks-$$VERSION-py3-none-any.whl" --target "./target/mocks" --platform manylinux2014_x86_64 --only-binary=:all:
# Copy lambda_handler file separately as it is not included within the package.
@cp lambda_handler.py ./target/mocks/
@cd ./target/mocks
@zip -r "../artifact.zip" .

@if [[ "$${IN_BUILD_CONTAINER}" == "true" ]]; then \
pyenv deactivate pathology-mocks; \
fi

.PHONY: build
build: clean-artifacts dependencies build-pathology build-mocks
@echo "Built artifacts for both pathology and mocks"


.PHONY: build-images
build-images: build # Build the project artefact @Pipeline
@mkdir -p infrastructure/images/pathology-api/resources/build
@cp -r pathology-api/target/pathology-api infrastructure/images/pathology-api/resources/build

@mkdir infrastructure/images/mocks/resources/build/
@cp mocks/target/artifact.zip infrastructure/images/mocks/resources/build/
@mkdir infrastructure/images/mocks/resources/build/mocks
@unzip infrastructure/images/mocks/resources/build/artifact.zip -d infrastructure/images/mocks/resources/build/mocks

@echo "Building Docker image using Docker. Utilising python version: ${PYTHON_VERSION} ..."
@$(docker) buildx build --load --platform=linux/amd64 --provenance=false --build-arg PYTHON_VERSION=${PYTHON_VERSION} -t localhost/pathology-api-image infrastructure/images/pathology-api
@echo "Docker image 'pathology-api-image' built successfully!"
Expand All @@ -48,18 +117,26 @@ build-images: build # Build the project artefact @Pipeline
@$(docker) buildx build --load --build-arg PYTHON_VERSION=${PYTHON_VERSION} -t localhost/api-gateway-mock-image infrastructure/images/api-gateway-mock
@echo "Docker image 'api-gateway-mock-image' built successfully!"

@echo "Building mocks Docker image using Docker. Utilising python version: ${PYTHON_VERSION} ..."
@$(docker) buildx build --load --platform=linux/amd64 --provenance=false --build-arg PYTHON_VERSION=${PYTHON_VERSION} -t localhost/mocks-image infrastructure/images/mocks
@echo "Docker image 'mocks-image' built successfully!"

publish: # Publish the project artefact @Pipeline
# TODO: Implement the artefact publishing step

deploy: clean-docker build-images # Deploy the project artefact to the target environment @Pipeline
$(docker) network create $(dockerNetwork) || echo "Docker network '$(dockerNetwork)' already exists."
$(docker) run --platform linux/amd64 --name pathology-api -p 5001:8080 --network $(dockerNetwork) -d localhost/pathology-api-image
$(docker) run --platform linux/amd64 --name pathology-api -p 5001:8080 --network $(dockerNetwork) -d localhost/pathology-api-image
$(docker) run --platform linux/amd64 --name mocks -p 5003:8080 --network $(dockerNetwork) -d localhost/mocks-image
$(docker) run --name api-gateway-mock -p 5002:5000 --network $(dockerNetwork) -d localhost/api-gateway-mock-image
$(docker) run --name api-gateway-mock-2 -p 5005:5000 -e TARGET_CONTAINER='MOCKS' --network $(dockerNetwork) -d localhost/api-gateway-mock-image

clean-artifacts:
@echo "Removing build artefacts..."
@rm -rf infrastructure/images/pathology-api/resources/build/
@rm -rf pathology-api/target && rm -rf pathology-api/dist
@rm -rf infrastructure/images/mocks/resources/build/
@rm -rf mocks/target && rm -rf mocks/dist

clean-docker: stop
@echo "Removing pathology API container..."
Expand All @@ -68,6 +145,12 @@ clean-docker: stop
@echo "Removing api-gateway-mock container..."
@$(docker) rm api-gateway-mock || echo "No api-gateway-mock container currently exists."

@echo "Removing mocks container..."
@$(docker) rm mocks || echo "No mocks container currently exists."

@echo "Removing api-gateway-mock-2 container..."
@$(docker) rm api-gateway-mock-2 || echo "No api-gateway-mock-2 container currently exists."

clean:: clean-artifacts clean-docker # Clean-up project resources (main) @Operations

.PHONY: stop
Expand All @@ -78,6 +161,12 @@ stop:
@echo "Stopping api-gateway-mock container..."
@$(docker) stop api-gateway-mock || echo "No api-gateway-mock container currently running."

@echo "Stopping mocks container..."
@$(docker) stop mocks || echo "No mocks container currently running."

@echo "Stopping api-gateway-mock-2 container..."
@$(docker) stop api-gateway-mock-2 || echo "No api-gateway-mock-2 container currently running."

config:: # Configure development environment (main) @Configuration
# Configure poetry to trust dev certificate if specified
@if [[ -n "$${DEV_CERTS_INCLUDED}" ]]; then \
Expand Down
45 changes: 0 additions & 45 deletions infrastructure/environments/preview/handler.py

This file was deleted.

Loading
Loading