Skip to content

RAA-7897: Replace S3 routing with EPC API Gateway lookup#324

Open
geberele wants to merge 16 commits into
masterfrom
raa-7897-epc-routing
Open

RAA-7897: Replace S3 routing with EPC API Gateway lookup#324
geberele wants to merge 16 commits into
masterfrom
raa-7897-epc-routing

Conversation

@geberele

@geberele geberele commented Jun 5, 2026

Copy link
Copy Markdown

Jira

RAA-7897

Summary

  • Removes the static AWS S3 targets.json routing pipeline (KVM credentials fetch → AWS Sig V4 signing → S3 ServiceCallout) from the BaRS proxy target endpoint
  • Replaces it with a dynamic call to the EPC API Gateway: GET /Endpoint?HealthcareService.identifier={system}|{value} using the decoded NHSD-Target-Identifier header
  • Establishes mTLS connection to the EPC API Gateway (using existing bars-client/cert keystore) — auth method TBD, see open decisions below
  • Extracts the address field from the first active Endpoint in the returned FHIR Bundle and uses it to route the request
  • Adds distinct OperationOutcome error responses for EPC 404 (endpoint not found → existing 404ProxyNotFound), 5xx/timeout (new 503EpcUnavailable), and malformed response (new 500EpcInvalidResponse)
  • Validate/decode steps (Python.DecodeBase64, Javascript.CheckTarget) now run before the EPC call to fail fast on bad identifier format

Files changed

Deleted (S3 pipeline): KVM.GetS3Credentials, AM-S3Request, JC-AWSSignV4, SC-CallS3, AssignMessage.Targets, Javascript.UnpackVars, Javascript.setTargetUrl, UnpackVars.js, SetTargetUrl.js

Created (EPC pipeline): KVM.GetEpcConfig, Javascript.BuildEpcPath + BuildEpcPath.js, AM.PrepareEpcRequest, SC.CallEpc, Javascript.ParseEpcResponse + ParseEpcResponse.js, RaiseFault.503EpcUnavailable, RaiseFault.500EpcInvalidResponse

Modified: bref-target.xml, CheckTargets.js, BarsLibrary.js, DecodeBase64String.py, HandleErrors.js, ErrorRepository.js

Open decisions (pending platform team confirmation)

⚠️ EPC authentication method — not yet confirmed

The current implementation uses mTLS (SC.CallEpc.xml with ClientAuthEnabled=true, bars-client/cert keystore). However, the EPC API Gateway currently uses HTTP API v2 which does not support mutual TLS, and an API-Key approach is also under consideration. The final auth method may be:

  • mTLS only — requires switching EPC infra to REST API Gateway and provisioning a client cert
  • API-Key only — store key in KVM, add x-api-key header in AM.PrepareEpcRequest.xml, remove ClientAuthEnabled from SC.CallEpc.xml
  • Both — mTLS + API-Key for defence in depth

This PR implements mTLS as a placeholder. SC.CallEpc.xml and AM.PrepareEpcRequest.xml are the only files that need updating once the decision is made.

Pre-deploy prerequisites

A new Apigee KVM booking-and-referral-epc-config must be created with:

  • epc_base_url — EPC API Gateway base URL
  • epc_organisation — base64-encoded FHIR Organization JSON for the proxy service identity
  • epc_api_key — (if API-Key auth is chosen) API key for EPC Gateway

Additional pending confirmations:

  • mTLS keystore: confirm if bars-client/cert is reused or a separate EPC keystore is needed
  • Proxy ODS code for epc_organisation service identity
  • Final error codes for Scenarios 4–6 (ticket notes "discuss with Richard")

Test plan

  • Run existing pytest tests/ suite — pre-flight and auth flow tests should pass unchanged
  • Add test cases to tests/test_target_identifier.py: EPC 200 active endpoint → correct routing, EPC 404 → 404 OperationOutcome, EPC 503 → 503 OperationOutcome, EPC malformed JSON → 500 OperationOutcome
  • Deploy to sandbox/dev Apigee environment; send GET /Slot with valid NHSD-Target-Identifier and confirm request reaches expected backend
  • Verify EPC auth method once confirmed and update SC.CallEpc.xml / AM.PrepareEpcRequest.xml accordingly

@geberele geberele requested a review from Valswyn-NHS June 5, 2026 15:16
Replaces the static S3 targets.json lookup with a dynamic call to the
EPC API Gateway. The proxy now queries GET /Endpoint?HealthcareService.identifier
using the decoded NHSD-Target-Identifier header, extracts the address field
from the first active Endpoint in the returned FHIR Bundle, and routes to it
via mTLS. Adds distinct OperationOutcome error responses for EPC 404 (no
endpoint found), 5xx/timeout (unavailable), and malformed response scenarios.
@geberele geberele force-pushed the raa-7897-epc-routing branch from 3f17f0c to 0a9d552 Compare June 5, 2026 15:20
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

pyyaml 5.4.1 was released before Python 3.10 existed and has no cp310
binary wheels. Building from source fails on modern setuptools because
the old setup.py references build_ext.cython_sources which no longer
exists. Upgrade to 6.0.2 which has cp310 wheels and proper PEP 517
support.

awscli 1.25.24 constrained PyYAML < 5.5, blocking the pyyaml upgrade.
Upgrade awscli to 1.32.0 (PyYAML < 6.1) and its pinned botocore to
1.34.0 and s3transfer to 0.9.0. All locked transitive deps (urllib3
1.26.9, colorama 0.4.4, rsa 4.7.2, docutils 0.16) still satisfy the
new version constraints.
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

The wheel URL for api-test-utils is on a private GitHub repo that the
CI runner cannot access, causing poetry install to fail. The package is
only needed for running Apigee e2e tests (tests/conftest.py,
tests/api_test.py), not for the CI build or version calculation.

Moving it to an optional group means `poetry install` skips it by
default. To run the e2e tests locally: `poetry install --with e2e`.
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

DecodeBase64String.py references the Apigee-injected 'flow' global, which pyflakes reports as F821 (undefined name). The .flake8 exclude entry is bypassed because the Makefile passes files explicitly via find|xargs. Mirror the existing sandbox exclusion in the find command.
@github-actions

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

Poetry 2.x validates the PEP 621 [project] table and requires 'name'. The leftover stub contained only an invalid 'python' key, so 'poetry run' (used by make lint) failed with 'project must contain [name] properties'. All real metadata already lives in [tool.poetry], so drop the stub.
@github-actions

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

…hash)

The committed lock was lock-version 2.0 with no per-package group info, so Poetry 2.x's 'poetry install' could not resolve the dev group and skipped flake8 ('Command not found: flake8' in make lint). Regenerated to lock-version 2.1 with explicit groups; no dependency versions changed.
@github-actions

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

The shared apigee-build template defaults python_version to 3.13. The pinned deps (aiohttp 3.8.1 -> frozenlist 1.3.0, etc.) use CPython internals removed in 3.12+ and fail to compile, so 'make install' (poetry install) failed and flake8 was never installed, breaking 'make lint'. Pin to 3.10 to match the intended runtime and the pinned dependency set.
@github-actions

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

The deploy post-deploy step ran 'make install-python' (poetry install) without a Python version pin, so it picked up the agent default (3.13), against which the pinned C-extension deps (frozenlist, aiohttp, typed-ast) fail to compile. Pin 3.10 to match the build pipeline.
@github-actions

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

SC.CallEpc used a fully-variable <URL>{private.epcBaseUrl}</URL>, which Apigee rejects at import with ProtocolMissingInURL. Hardcode the https:// scheme (the callout is mTLS) and derive private.epcHost in BuildEpcPath by stripping any scheme the KVM value may carry, so the target resolves correctly regardless of how epc_base_url is stored.
@github-actions

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

Apigee's Rhino engine rejects `return` at script top level (javascript.exec.CompilationError), failing deployment. Wrap the body in an IIFE so the early-exit returns are valid; behaviour is unchanged since the script communicates only via context variables.
@github-actions

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

The dist artifact copies pyproject.toml (which declares readme = 'README.md') but not README.md, so 'poetry install' in the post-deploy step fails resolving the root project's readme path. Add README.md to _dist_include so the packaged artifact is self-consistent.
@github-actions

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

The project is not a Python package (no package directory, no packages config), so 'poetry install' fails trying to install the root project. The post-deploy step only needs dependencies to run pytest, so install deps without the root package, as Poetry itself recommends.
@github-actions

Copy link
Copy Markdown

This branch is work on a ticket in the NHS Digital APM JIRA Project. Here's a handy link to the ticket:

RAA-7897

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant