Skip to content

Commit

Permalink
AEA-3534 Modify Spine client code so that it doesn't call Spine if th…
Browse files Browse the repository at this point in the history
…e Certificate is not configured (#166)

## Summary

- ❗ Breaking Change
- ⚠️ Potential issues that might be caused by this change

### Details

Modify Spine client code so that it doesn't call Spine if the
Certificate is not configured

## Reviews Required

- [x] Dev
- [ ] Test
- [x] Tech Author
- [ ] Product Owner

## Review Checklist

ℹ️ This section is to be filled in by the
**reviewer**.

- [ ] I have reviewed the changes in this PR and they fill all or part
of the acceptance criteria of the ticket, and the code is in a mergeable
state.
- [ ] If there were infrastructure, operational, or build changes, I
have made sure there is sufficient evidence that the changes will work.
- [ ] I have ensured the jira ticket has been updated with the github
pull request link
  • Loading branch information
kris-szlapa authored Sep 26, 2023
1 parent 789a6b8 commit 9ffc61a
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 2 deletions.
30 changes: 30 additions & 0 deletions packages/getMyPrescriptions/src/getMyPrescriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,36 @@ const lambdaHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayPro
const spineClient = createSpineClient()

try {
const isCertificateConfigured = spineClient.isCertificateConfigured()
if (!isCertificateConfigured) {
const errorResponseBody = {
resourceType: "OperationOutcome",
issue: [
{
code: "security",
severity: "fatal",
details: {
coding: [
{
system: "https://fhir.nhs.uk/CodeSystem/http-error-codes",
code: "SERVER_ERROR",
display: "500: The Server has encountered an error processing the request."
}
]
},
diagnostics: "Spine certificate is not configured"
}
]
}
return {
statusCode: 500,
body: JSON.stringify(errorResponseBody),
headers: {
"Content-Type": "application/fhir+json",
"Cache-Control": "no-cache"
}
}
}
const returnData = await spineClient.getPrescriptions(event.headers, logger)
const resBody = returnData.data
resBody.id = xRequestId
Expand Down
37 changes: 37 additions & 0 deletions packages/getMyPrescriptions/tests/test-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ const responseStatus500 = {
]
}

const responseNotConfCertStatus500 = {
resourceType: "OperationOutcome",
issue: [
{
code: "security",
severity: "fatal",
details: {
coding: [
{
system: "https://fhir.nhs.uk/CodeSystem/http-error-codes",
code: "SERVER_ERROR",
display: "500: The Server has encountered an error processing the request."
}
]
},
diagnostics: "Spine certificate is not configured"
}
]
}

type spineFailureTestData = {
httpResponseCode: number
spineStatusCode: string
Expand Down Expand Up @@ -210,6 +230,23 @@ describe("Unit test for app handler", function () {
})
expect(JSON.parse(result.body)).toEqual(responseStatus500)
})

it("return error when the certificate is not configured", async () => {
process.env.SpinePublicCertificate = "ChangeMe"
process.env.SpinePrivateKey = "ChangeMe"
process.env.SpineCAChain = "ChangeMe"

mock.onGet("https://live/mm/patientfacingprescriptions").reply(500, {resourceType: "Bundle"})
const event: APIGatewayProxyEvent = JSON.parse(exampleEvent)
const result: APIGatewayProxyResult = await handler(event, dummyContext)

expect(result.statusCode).toBe(500)
expect(result.headers).toEqual({
"Content-Type": "application/fhir+json",
"Cache-Control": "no-cache"
})
expect(JSON.parse(result.body)).toEqual(responseNotConfCertStatus500)
})
})

export {}
9 changes: 9 additions & 0 deletions packages/spineClient/src/live-spine-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,13 @@ export class LiveSpineClient implements SpineClient {
return serviceHealthCheck(process.env.healthCheckUrl, logger, new Agent())
}
}

isCertificateConfigured(): boolean {
// Check if the required certificate-related environment variables are defined
return (
process.env.SpinePublicCertificate !== "ChangeMe" &&
process.env.SpinePrivateKey !== "ChangeMe" &&
process.env.SpineCAChain !== "ChangeMe"
)
}
}
5 changes: 5 additions & 0 deletions packages/spineClient/src/sandbox-spine-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@ export class SandboxSpineClient implements SpineClient {
// This is not implemented as sandbox lambda does not use this code
throw new Error("INTERACTION_NOT_SUPPORTED_BY_SANDBOX")
}

isCertificateConfigured(): boolean {
// In the sandbox environment, assume the certificate is always configured
return true
}
}
1 change: 1 addition & 0 deletions packages/spineClient/src/spine-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {AxiosResponse} from "axios"
export interface SpineClient {
getStatus(logger: Logger): Promise<StatusCheckResponse>
getPrescriptions(inboundHeaders: APIGatewayProxyEventHeaders, logger: Logger): Promise<AxiosResponse>
isCertificateConfigured(): boolean
}

export function createSpineClient(): SpineClient {
Expand Down
22 changes: 20 additions & 2 deletions packages/statusLambda/src/statusLambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,29 @@ const lambdaHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayPro

const spineClient = createSpineClient()

const spineStatus = await spineClient.getStatus(logger)

const commitId = process.env.COMMIT_ID
const versionNumber = process.env.VERSION_NUMBER

const isCertificateConfigured = spineClient.isCertificateConfigured()

if (!isCertificateConfigured) {
return {
statusCode: 200,
body: JSON.stringify({
commitId: commitId,
versionNumber: versionNumber,
status: "pass",
message: "Spine certificate is not configured"
}),
headers: {
"Content-Type": "application/health+json",
"Cache-Control": "no-cache"
}
}
}

const spineStatus = await spineClient.getStatus(logger)

return {
statusCode: 200,
body: JSON.stringify({
Expand Down
84 changes: 84 additions & 0 deletions packages/statusLambda/tests/test-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ const mock = new MockAdapter(axios)
const dummyContext = ContextExamples.helloworldContext

describe("Unit test for status check", function () {
let originalEnv: {[key: string]: string | undefined}
afterEach(() => {
process.env = {...originalEnv}
mock.reset()
})

Expand Down Expand Up @@ -76,6 +78,19 @@ describe("Unit test for status check", function () {
})
})

it("checks if the certificate is always configured for the sandbox", async () => {
process.env.TargetSpineServer = "sandbox"
process.env.SpinePublicCertificate = "ChangeMe"
process.env.SpinePrivateKey = "ChangeMe"
process.env.SpineCAChain = "ChangeMe"

const result: APIGatewayProxyResult = await handler(mockAPIGatewayProxyEvent, dummyContext)

expect(result.statusCode).toEqual(200)
const result_body = JSON.parse(result.body)
expect(result_body).not.toHaveProperty("message")
})

it("returns success when spine check succeeds", async () => {
mock.onGet("https://live/healthcheck").reply(200, {})
process.env.TargetSpineServer = "live"
Expand Down Expand Up @@ -143,4 +158,73 @@ describe("Unit test for status check", function () {
expect(result_body.spineStatus.timeout).toEqual("true")
expect(result_body.spineStatus.responseCode).toEqual(500)
})

it("returns success when Spine check succeeds and the certificate is not configured", async () => {
mock.onGet("https://live/healthcheck").reply(200, {})
process.env.TargetSpineServer = "live"
process.env.SpinePublicCertificate = "ChangeMe"
process.env.SpinePrivateKey = "ChangeMe"
process.env.SpineCAChain = "ChangeMe"

const result: APIGatewayProxyResult = await handler(mockAPIGatewayProxyEvent, dummyContext)

expect(result.statusCode).toEqual(200)
const result_body = JSON.parse(result.body)
expect(result_body.status).toEqual("pass")
expect(result_body.message).toEqual("Spine certificate is not configured")
})

it("returns success when Spine check succeeds without SpinePublicCertificate", async () => {
mock.onGet("https://live/healthcheck").reply(200, {})
process.env.TargetSpineServer = "live"
process.env.SpinePublicCertificate = "ChangeMe"

const result: APIGatewayProxyResult = await handler(mockAPIGatewayProxyEvent, dummyContext)

expect(result.statusCode).toEqual(200)
const result_body = JSON.parse(result.body)
expect(result_body.status).toEqual("pass")
expect(result_body.message).toEqual("Spine certificate is not configured")
})

it("returns success when Spine check succeeds without SpinePrivateKey", async () => {
mock.onGet("https://live/healthcheck").reply(200, {})
process.env.TargetSpineServer = "live"
process.env.SpinePrivateKey = "ChangeMe"

const result: APIGatewayProxyResult = await handler(mockAPIGatewayProxyEvent, dummyContext)

expect(result.statusCode).toEqual(200)
const result_body = JSON.parse(result.body)
expect(result_body.status).toEqual("pass")
expect(result_body.message).toEqual("Spine certificate is not configured")
})

it("returns success when Spine check succeeds without SpineCAChain", async () => {
mock.onGet("https://live/healthcheck").reply(200, {})
process.env.TargetSpineServer = "live"
process.env.SpineCAChain = "ChangeMe"

const result: APIGatewayProxyResult = await handler(mockAPIGatewayProxyEvent, dummyContext)

expect(result.statusCode).toEqual(200)
const result_body = JSON.parse(result.body)
expect(result_body.status).toEqual("pass")
expect(result_body.message).toEqual("Spine certificate is not configured")
})

it("returns failure when Spine check fails and the certificate is configured", async () => {
mock.onGet("https://live/healthcheck").reply(500, {})
process.env.TargetSpineServer = "live"

const result: APIGatewayProxyResult = await handler(mockAPIGatewayProxyEvent, dummyContext)

expect(result.statusCode).toEqual(200)
const result_body = JSON.parse(result.body)
expect(result_body).not.toHaveProperty("message")
expect(result_body.status).toEqual("error")
expect(result_body.spineStatus.status).toEqual("error")
expect(result_body.spineStatus.timeout).toEqual("false")
expect(result_body.spineStatus.responseCode).toEqual(500)
})
})

0 comments on commit 9ffc61a

Please sign in to comment.