Skip to content
Draft
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
1 change: 1 addition & 0 deletions lambdas/file-scanner-lambda/src/apis/sqs-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ async function processRecord(
messageReference: event.data.messageReference,
senderId: event.data.senderId,
createdAt: event.time,
traceparent: event.traceparent,
});

if (result.outcome === 'failed') {
Expand Down
2 changes: 2 additions & 0 deletions lambdas/file-scanner-lambda/src/app/file-scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface ScanFileMetadata {
messageReference: string;
senderId: string;
createdAt: string;
traceparent: string;
}

export type ScanFileResult = {
Expand Down Expand Up @@ -158,6 +159,7 @@ export class FileScanner {
messageReference: metadata.messageReference,
senderId: metadata.senderId,
createdAt: metadata.createdAt,
traceparent: metadata.traceparent,
},
};

Expand Down
2 changes: 2 additions & 0 deletions lambdas/mesh-acknowledge/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ boto3>=1.28.62
pyopenssl>=24.2.1
pydantic>=2.0.0
structlog>=21.5.0
opentelemetry-api>=1.25.0
opentelemetry-sdk>=1.25.0
-e ../../src/digital-letters-events
-e ../../utils/py-mock-mesh
-e ../../utils/py-utils
11 changes: 9 additions & 2 deletions lambdas/mesh-download/mesh_download/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ def __init__(self, **kwargs):
def process_sqs_message(self, sqs_record):
try:
validated_event = self._parse_and_validate_event(sqs_record)
logger = self.__log.bind(mesh_message_id=validated_event.data.meshMessageId)
logger = self.__log.bind(
mesh_message_id=validated_event.data.meshMessageId,
traceparent=validated_event.traceparent,
)

logger.info("Processing MESH download request")
self._handle_download(validated_event, logger)
Expand Down Expand Up @@ -106,6 +109,8 @@ def _store_message_content(self, sender_id, message_reference, message_content,
def _publish_downloaded_event(self, incoming_event, message_uri):
"""
Publishes a MESHInboxMessageDownloaded event.
The EventPublisher will derive a child traceparent from the incoming traceparent
automatically, preserving the trace-id across this service hop.
"""
now = datetime.now(timezone.utc).isoformat()

Expand Down Expand Up @@ -137,5 +142,7 @@ def _publish_downloaded_event(self, incoming_event, message_uri):
"Published MESHInboxMessageDownloaded event",
sender_id=incoming_event.data.senderId,
message_uri=message_uri,
message_reference=incoming_event.data.messageReference
message_reference=incoming_event.data.messageReference,
incoming_traceparent=incoming_event.traceparent,
outgoing_traceparent=cloud_event['traceparent'],
)
2 changes: 2 additions & 0 deletions lambdas/mesh-download/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ urllib3>=1.26.19,<2.0.0
idna>=3.7
requests>=2.32.0
pyopenssl>=24.2.1
opentelemetry-api>=1.25.0
opentelemetry-sdk>=1.25.0
-e ../../src/digital-letters-events
-e ../../utils/py-mock-mesh
-e ../../utils/py-utils
7 changes: 4 additions & 3 deletions lambdas/mesh-poll/mesh_poll/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def process_message(self, message):
def _publish_mesh_inbox_message_received_event(self, event_detail):
"""
Publishes a MESHInboxMessageReceived event for the retriever component.
The EventPublisher will create a root traceparent automatically.
"""
now = datetime.now(timezone.utc).isoformat()

Expand All @@ -167,7 +168,6 @@ def _publish_mesh_inbox_message_received_event(self, event_detail):
'recordedtime': now,
'severitynumber': 2,
'severitytext': 'INFO',
'traceparent': '00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01',
'dataschema': (
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/'
'2025-10-draft/data/digital-letters-mesh-inbox-message-received-data.schema.json'
Expand All @@ -185,11 +185,13 @@ def _publish_mesh_inbox_message_received_event(self, event_detail):

self.__log.info("Published MESHInboxMessageReceived event",
mesh_message_id=event_detail["data"]["meshMessageId"],
sender_id=event_detail["data"]["senderId"])
sender_id=event_detail["data"]["senderId"],
traceparent=cloud_event['traceparent'])

def _publish_mesh_inbox_message_invalid_event(self, event_detail):
"""
Publishes a MESHInboxMessageInvalid event when a message fails validation.
The EventPublisher will create a root traceparent automatically.
"""
now = datetime.now(timezone.utc).isoformat()

Expand All @@ -203,7 +205,6 @@ def _publish_mesh_inbox_message_invalid_event(self, event_detail):
'recordedtime': now,
'severitynumber': 3,
'severitytext': 'WARN',
'traceparent': '00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01',
'dataschema': (
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/'
'2025-10-draft/data/digital-letters-mesh-inbox-message-invalid-data.schema.json'
Expand Down
2 changes: 2 additions & 0 deletions lambdas/mesh-poll/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ idna>=3.7
requests>=2.32.0
pyopenssl>=24.2.1
pydantic>=2.0.0
opentelemetry-api>=1.25.0
opentelemetry-sdk>=1.25.0
-e ../../src/digital-letters-events
-e ../../utils/py-mock-mesh
-e ../../utils/py-utils
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type ObjectMetadata = {
senderId: string;
messageReference: string;
createdAt: string;
traceparent?: string;
};

type ObjectsFromEvent = {
Expand All @@ -34,6 +35,7 @@ const SCAN_RESULT_STATUS_NO_THREATS_FOUND = 'NO_THREATS_FOUND';
const METADATA_CREATED_AT = 'createdat';
const METADATA_MESSAGE_REFERENCE = 'messagereference';
const METADATA_SENDER_ID = 'senderid';
const METADATA_TRACEPARENT = 'traceparent';

/**
* Utility function to extract a subset of the object key for logging purposes.
Expand Down Expand Up @@ -121,6 +123,7 @@ export class MoveFileHandler {
const createdAt = metadataMap.get(METADATA_CREATED_AT);
const messageReference = metadataMap.get(METADATA_MESSAGE_REFERENCE);
const senderId = metadataMap.get(METADATA_SENDER_ID);
const traceparent = metadataMap.get(METADATA_TRACEPARENT);

if (!messageReference || !senderId || !createdAt) {
return null;
Expand All @@ -137,6 +140,7 @@ export class MoveFileHandler {
senderId,
messageReference,
createdAt,
traceparent,
};
}

Expand All @@ -160,6 +164,7 @@ export class MoveFileHandler {
metadata.senderId,
`s3://${destinationBucket}/${objectKey}`,
metadata.createdAt,
metadata.traceparent,
);
} else {
destinationBucket = this.quarantineBucketName;
Expand All @@ -176,6 +181,7 @@ export class MoveFileHandler {
metadata.senderId,
`s3://${destinationBucket}/${objectKey}`,
metadata.createdAt,
metadata.traceparent,
);
}

Expand Down
7 changes: 6 additions & 1 deletion lambdas/move-scanned-files-lambda/src/domain/mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ function createEventWithCommonFields(
senderId: string,
letterUri: string,
createdAt: string,
traceparent?: string,
): FileSafe | FileQuarantined {
return {
specversion: '1.0',
id: randomUUID(),
subject: `customer/${senderId}/recipient/${messageReference}`,
source:
'/nhs/england/notify/production/primary/data-plane/digitalletters/print', // Note CCM-13892.
traceparent: '00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01', // Note CCM-14255.
traceparent: traceparent ?? '', // EventPublisher will derive child or create root
type: isFileSafe
? 'uk.nhs.notify.digital.letters.print.file.safe.v1'
: 'uk.nhs.notify.digital.letters.print.file.quarantined.v1',
Expand All @@ -36,13 +37,15 @@ export function createFileSafeEvent(
senderId: string,
letterUri: string,
createdAt: string,
traceparent?: string,
): FileSafe {
return createEventWithCommonFields(
true,
messageReference,
senderId,
letterUri,
createdAt,
traceparent,
) as FileSafe;
}

Expand All @@ -51,12 +54,14 @@ export function createFileQuarantinedEvent(
senderId: string,
letterUri: string,
createdAt: string,
traceparent?: string,
): FileQuarantined {
return createEventWithCommonFields(
false,
messageReference,
senderId,
letterUri,
createdAt,
traceparent,
) as FileQuarantined;
}
16 changes: 16 additions & 0 deletions lambdas/pdm-poll-lambda/src/__tests__/apis/sqs-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,24 @@

jest.mock('node:crypto', () => ({
randomUUID: jest.fn(),
randomBytes: jest.fn(),
}));

// eslint-disable-next-line @typescript-eslint/no-require-imports
const { randomBytes } = require('node:crypto');

const mockRandomUUID = randomUUID as jest.MockedFunction<typeof randomUUID>;
const mockRandomBytes = randomBytes as jest.MockedFunction<
typeof import('node:crypto').randomBytes
>;
const mockDate = jest.spyOn(Date.prototype, 'toISOString');
mockRandomUUID.mockReturnValue('550e8400-e29b-41d4-a716-446655440001');
mockRandomBytes.mockImplementation(() => Buffer.from('aabbccdd11223344', 'hex'));

Check failure on line 30 in lambdas/pdm-poll-lambda/src/__tests__/apis/sqs-handler.test.ts

View workflow job for this annotation

GitHub Actions / Test stage / Linting

Replace `·Buffer.from('aabbccdd11223344',·'hex')` with `⏎··Buffer.from('aabbccdd11223344',·'hex'),⏎`
mockDate.mockReturnValue('2023-06-20T12:00:00.250Z');

const DERIVED_TRACEPARENT =
'00-0af7651916cd43dd8448eb211c80319c-aabbccdd11223344-01';

const handler = createHandler({
eventPublisher,
logger,
Expand Down Expand Up @@ -51,6 +62,7 @@
id: '550e8400-e29b-41d4-a716-446655440001',
time: '2023-06-20T12:00:00.250Z',
recordedtime: '2023-06-20T12:00:00.250Z',
traceparent: DERIVED_TRACEPARENT,
dataschema:
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-pdm-resource-available-data.schema.json',
type: 'uk.nhs.notify.digital.letters.pdm.resource.available.v1',
Expand Down Expand Up @@ -90,6 +102,7 @@
id: '550e8400-e29b-41d4-a716-446655440001',
time: '2023-06-20T12:00:00.250Z',
recordedtime: '2023-06-20T12:00:00.250Z',
traceparent: DERIVED_TRACEPARENT,
dataschema:
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-pdm-resource-unavailable-data.schema.json',
type: 'uk.nhs.notify.digital.letters.pdm.resource.unavailable.v1',
Expand Down Expand Up @@ -132,6 +145,7 @@
id: '550e8400-e29b-41d4-a716-446655440001',
time: '2023-06-20T12:00:00.250Z',
recordedtime: '2023-06-20T12:00:00.250Z',
traceparent: DERIVED_TRACEPARENT,
dataschema:
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-pdm-resource-available-data.schema.json',
type: 'uk.nhs.notify.digital.letters.pdm.resource.available.v1',
Expand Down Expand Up @@ -174,6 +188,7 @@
id: '550e8400-e29b-41d4-a716-446655440001',
time: '2023-06-20T12:00:00.250Z',
recordedtime: '2023-06-20T12:00:00.250Z',
traceparent: DERIVED_TRACEPARENT,
type: 'uk.nhs.notify.digital.letters.pdm.resource.unavailable.v1',
data: {
messageReference:
Expand Down Expand Up @@ -219,6 +234,7 @@
id: '550e8400-e29b-41d4-a716-446655440001',
time: '2023-06-20T12:00:00.250Z',
recordedtime: '2023-06-20T12:00:00.250Z',
traceparent: DERIVED_TRACEPARENT,
dataschema:
'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-pdm-resource-retries-exceeded-data.schema.json',
type: 'uk.nhs.notify.digital.letters.pdm.resource.retries.exceeded.v1',
Expand Down
28 changes: 21 additions & 7 deletions lambdas/pdm-poll-lambda/src/apis/sqs-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,16 +184,30 @@ export const createHandler = ({

if (pdmAvailability === 'unavailable') {
if (retries >= pollMaxRetries) {
retriesExceededEvents.push(
generateRetriesExceededEvent(event, retries),
);
const outgoing = generateRetriesExceededEvent(event, retries);
logger.info({
description: 'TraceContext hop',
incoming_traceparent: event.traceparent,
outgoing_traceparent: outgoing.traceparent,
});
retriesExceededEvents.push(outgoing);
} else {
unavailableEvents.push(generateUnavailableEvent(event, retries));
const outgoing = generateUnavailableEvent(event, retries);
logger.info({
description: 'TraceContext hop',
incoming_traceparent: event.traceparent,
outgoing_traceparent: outgoing.traceparent,
});
unavailableEvents.push(outgoing);
}
} else {
availableEvents.push(
generateAvailableEvent(event, nhsNumber, odsCode),
);
const outgoing = generateAvailableEvent(event, nhsNumber, odsCode);
logger.info({
description: 'TraceContext hop',
incoming_traceparent: event.traceparent,
outgoing_traceparent: outgoing.traceparent,
});
availableEvents.push(outgoing);
}
} catch (error: any) {
logger.warn({
Expand Down
2 changes: 2 additions & 0 deletions lambdas/report-sender/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ idna>=3.7
requests>=2.32.0
pyopenssl>=24.2.1
pydantic>=2.0.0
opentelemetry-api>=1.25.0
opentelemetry-sdk>=1.25.0
-e ../../src/digital-letters-events
-e ../../utils/py-mock-mesh
-e ../../utils/py-utils
Loading
Loading