Skip to content
Merged
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
12 changes: 8 additions & 4 deletions .github/workflows/pr-lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check ticket name conforms to requirements
run: echo ${{ github.event.pull_request.head.ref }} | grep -i -E -q "(ccm-[0-9]+)|(dependabot\/)"
env:
BRANCH_REF: ${{ github.event.pull_request.head.ref }}
run: echo "$BRANCH_REF" | grep -i -E -q "(ccm-[0-9]+)|(dependabot\/)"
continue-on-error: true

- name: Grab ticket name
if: contains(github.event.pull_request.head.ref, 'ccm-') || contains(github.event.pull_request.head.ref, 'CCM-')
run: echo ::set-env name=TICKET_NAME::$(echo ${{ github.event.pull_request.head.ref }} | grep -i -o '\(ccm-[0-9]\+\)' | tr '[:lower:]' '[:upper:]')
continue-on-error: true
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
BRANCH_REF: ${{ github.event.pull_request.head.ref }}
run: |
TICKET=$(echo "$BRANCH_REF" | grep -i -o '\(ccm-[0-9]\+\)' | tr '[:lower:]' '[:upper:]')
echo "TICKET_NAME=$TICKET" >> $GITHUB_ENV
continue-on-error: true

- name: Comment on PR with link to JIRA ticket
if: contains(github.event.pull_request.head.ref, 'ccm-') || contains(github.event.pull_request.head.ref, 'CCM-')
Expand Down
51 changes: 23 additions & 28 deletions nhsd-git-secrets/nhsd-git-secrets.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,43 +19,38 @@

FROM ubuntu:24.10

RUN echo "Installing required modules"
RUN apt-get update \
&& apt-get -y install curl git build-essential \
&& apt-get clean
RUN echo "Installing required modules" \
&& apt-get update \
&& apt-get -y install build-essential curl git \
&& apt-get clean \
&& echo "Copying source files"

# By default, we copy the entire project into the dockerfile for secret scanning
# Tweak that COPY if you only want some of the source
RUN echo "Copying source files"
WORKDIR /secrets-scanner
COPY . source
RUN ls -l source

RUN echo "Downloading secrets scanner"
RUN curl https://codeload.github.com/awslabs/git-secrets/tar.gz/master | tar -xz --strip=1 git-secrets-master

RUN echo "Installing secrets scanner"
RUN make install
RUN ls -l source \
&& echo "Downloading secrets scanner" \
&& curl https://codeload.github.com/awslabs/git-secrets/tar.gz/master | tar -xz --strip=1 git-secrets-master \
&& RUN echo "Installing secrets scanner" \
&& RUN make install \
&& echo "Configuring git"

# even though running secrets scanner on a folder, must still be in some kind of git repo
# for the git-secrets config to attach to something
# so init an empty git repo here
RUN echo "Configuring git"
WORKDIR /secrets-scanner/source
RUN git init

RUN echo "Downloading regex files from engineering-framework"
RUN curl https://codeload.github.com/NHSDigital/software-engineering-quality-framework/tar.gz/main | tar -xz --strip=3 software-engineering-quality-framework-main/tools/nhsd-git-secrets/nhsd-rules-deny.txt
RUN git init \
&& echo "Downloading regex files from engineering-framework" \
&& curl https://codeload.github.com/NHSDigital/software-engineering-quality-framework/tar.gz/main | tar -xz --strip=3 software-engineering-quality-framework-main/tools/nhsd-git-secrets/nhsd-rules-deny.txt \
&& echo "Copying allowed secrets list"

RUN echo "Copying allowed secrets list"
COPY .gitallowed .
RUN echo .gitallowed

# Register additional providers: adds AWS by default
RUN echo "Configuring secrets scanner"
RUN /secrets-scanner/git-secrets --register-aws
RUN /secrets-scanner/git-secrets --add-provider -- cat nhsd-rules-deny.txt

# build will fail here, if secrets are found
RUN echo "Running scan..."
RUN /secrets-scanner/git-secrets --scan -r .
RUN echo .gitallowed \
# Register additional providers: adds AWS by default
&& echo "Configuring secrets scanner" \
&& /secrets-scanner/git-secrets --register-aws \
&& /secrets-scanner/git-secrets --add-provider -- cat nhsd-rules-deny.txt \
# build will fail here, if secrets are found
&& echo "Running scan..." \
&& /secrets-scanner/git-secrets --scan -r .
2 changes: 1 addition & 1 deletion proxies/shared/resources/jsc/HealthCheck.SetResponse.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function json_tryparse(raw) {
try {
return JSON.parse(raw);
}
catch (e) {
catch (e) { // NOSONAR
return raw;
}
}
Expand Down
176 changes: 108 additions & 68 deletions proxies/shared/resources/jsc/MessageBatches.Create.Validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,90 +5,130 @@
* It is called by the JavaScript.MessageBatches.Create.Validate policy.
*/

var content = context.getVariable("request.content")
var errors = []
var content = context.getVariable("request.content");
var errors = [];

var all
var all;
var parseFailed = false;
try {
all = JSON.parse(content)
all = JSON.parse(content);
} catch (e) {
errors.push(invalidError("/"))
errors.push(invalidError("/"));
parseFailed = true;
}

function validateBatchMessage(errors, message, index, seenMessages) {
var pointer = "/data/attributes/messages/" + index;

const validate = () => {
if (all) {
var seenMessages = {};
var data = all.data;

const validDataObject = validateObject(errors, data, "/data")
if (validDataObject) {
validateConstantString(errors, data.type, "/data/type", "MessageBatch")

const validAttributesObject = validateObject(errors, data.attributes, "/data/attributes")
if (validAttributesObject) {

validateUuid(errors, data.attributes.routingPlanId, "/data/attributes/routingPlanId")

validateString(errors, data.attributes.messageBatchReference, "/data/attributes/messageBatchReference")

const validArray = validateArray(errors, data.attributes.messages, "/data/attributes/messages", 1)
if (validArray) {
if (data.attributes.messages.length > 45000) {
errors.push(tooManyItemsError("/data/attributes/messages"));
return null;
}
data.attributes.messages.forEach((message, index) => {
var pointer = "/data/attributes/messages/" + index;
// Limit the amount of errors returned to 100 entries
if (errors.length >= 100) {
errors = errors.slice(0, 100);
return null;
}

if (isUndefined(message)) {
errors.push(missingError(pointer));
} else if (message === null) {
errors.push(nullError(pointer));
} else if (typeof message !== "object" || Array.isArray(message)) {
errors.push(invalidError(pointer));
} else {
// Limit the amount of errors returned to 100 entries
if (errors.length >= 100) {
return null;
}

var pointer = "/data/attributes/messages/" + index + "/messageReference";
const validMessageReference = validateString(errors, message.messageReference, pointer)
if (validMessageReference) {
if (seenMessages[message.messageReference]) {
errors.push(duplicateError(pointer));
} else {
seenMessages[message.messageReference] = 1;
}
}
if (!validateObject(errors, message, pointer)) return;

pointer = "/data/attributes/messages/" + index + "/messageReference";
const validMessageReference = validateString(
errors,
message.messageReference,
pointer
);
if (validMessageReference) {
if (seenMessages[message.messageReference]) {
errors.push(duplicateError(pointer));
} else {
seenMessages[message.messageReference] = 1;
}
}

const validRecipientObject = validateObject(errors, message.recipient, "/data/attributes/messages/" + index + "/recipient")
if (validRecipientObject) {
const validRecipientObject = validateObject(
errors,
message.recipient,
"/data/attributes/messages/" + index + "/recipient"
);
if (validRecipientObject) {
validateNhsNumber(
errors,
message.recipient.nhsNumber,
"/data/attributes/messages/" + index + "/recipient/nhsNumber"
);
}

validateNhsNumber(errors, message.recipient.nhsNumber, "/data/attributes/messages/" + index + "/recipient/nhsNumber")
}
if (!isUndefined(message.originator)) {
const validOriginatorObject = validateObject(
errors,
message.originator,
"/data/attributes/messages/" + index + "/originator"
);
if (validOriginatorObject) {
validateOdsCode(
errors,
message.originator.odsCode,
"/data/attributes/messages/" + index + "/originator/odsCode"
);
}
}

if (!isUndefined(message.originator)) {
const validOriginatorObject = validateObject(errors, message.originator, "/data/attributes/messages/" + index + "/originator")
if (validOriginatorObject) {
validateOdsCode(errors, message.originator.odsCode, "/data/attributes/messages/" + index + "/originator/odsCode")
}
}
pointer = "/data/attributes/messages/" + index + "/personalisation";
if (!isUndefined(message.personalisation)) {
validateObject(errors, message.personalisation, pointer);
}
}

pointer = "/data/attributes/messages/" + index + "/personalisation";
if (!isUndefined(message.personalisation)) {
validateObject(errors, message.personalisation, pointer)
}
}
});
}
function validateBatchAttributes(errors, attributes, seenMessages) {
const validAttributesObject = validateObject(
errors,
attributes,
"/data/attributes"
);
if (validAttributesObject) {
validateUuid(
errors,
attributes.routingPlanId,
"/data/attributes/routingPlanId"
);
validateString(
errors,
attributes.messageBatchReference,
"/data/attributes/messageBatchReference"
);

const validArray = validateArray(
errors,
attributes.messages,
"/data/attributes/messages",
1
);
if (validArray) {
if (attributes.messages.length > 45000) {
errors.push(tooManyItemsError("/data/attributes/messages"));
return null;
}
attributes.messages.forEach((message, index) => {
validateBatchMessage(errors, message, index, seenMessages);
});
}
}
}

function validateBatchData(errors, data, seenMessages) {
const validDataObject = validateObject(errors, data, "/data");
if (validDataObject) {
validateConstantString(errors, data.type, "/data/type", "MessageBatch");
validateBatchAttributes(errors, data.attributes, seenMessages);
}
}

const validate = () => {
if (parseFailed) return;
if (all) {
var seenMessages = {};
var data = all.data;
validateBatchData(errors, data, seenMessages);
}
errors = errors.slice(0, 100);
};

validate();

if (errors.length > 0) {
Expand Down
69 changes: 40 additions & 29 deletions proxies/shared/resources/jsc/Messages.Create.Validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,48 +10,59 @@ var content = context.getVariable("request.content")
var errors = []

var all
var parseFailed = false;
try {
all = JSON.parse(content)
} catch (e) {
errors.push(invalidError("/"))
parseFailed = true;
}

function validateRecipient(errors, recipient) {
const validRecipientObject = validateObject(errors, recipient, "/data/attributes/recipient");
if (validRecipientObject) {
validateNhsNumber(errors, recipient.nhsNumber, "/data/attributes/recipient/nhsNumber");
}
}

function validateOriginator(errors, originator) {
const validOriginatorObject = validateObject(errors, originator, "/data/attributes/originator");
if (validOriginatorObject) {
validateOdsCode(errors, originator.odsCode, "/data/attributes/originator/odsCode");
}
}

const validate = () => {
if (all) {
var data = all.data;

const validDataObject = validateObject(errors, data, "/data")
if (validDataObject) {

validateConstantString(errors, data.type, "/data/type", "Message")

const validAttributesObject = validateObject(errors, data.attributes, "/data/attributes")
if (validAttributesObject) {

validateUuid(errors, data.attributes.routingPlanId, "/data/attributes/routingPlanId")
function validateAttributes(errors, attributes) {
const validAttributesObject = validateObject(errors, attributes, "/data/attributes");
if (validAttributesObject) {
validateUuid(errors, attributes.routingPlanId, "/data/attributes/routingPlanId");
validateString(errors, attributes.messageReference, "/data/attributes/messageReference");

validateString(errors, data.attributes.messageReference, "/data/attributes/messageReference")
validateRecipient(errors, attributes.recipient);

const validRecipientObject = validateObject(errors, data.attributes.recipient, "/data/attributes/recipient")
if (validRecipientObject) {
if (!isUndefined(attributes.originator)) {
validateOriginator(errors, attributes.originator);
}

validateNhsNumber(errors, data.attributes.recipient.nhsNumber, "/data/attributes/recipient/nhsNumber")
}
if (!isUndefined(attributes.personalisation)) {
validateObject(errors, attributes.personalisation, "/data/attributes/personalisation");
}
}
}

if (!isUndefined(data.attributes.originator)) {
const validOriginatorObject = validateObject(errors, data.attributes.originator, "/data/attributes/originator")
if (validOriginatorObject) {
validateOdsCode(errors, data.attributes.originator.odsCode, "/data/attributes/originator/odsCode")
}
}
function validateData(errors, data) {
const validDataObject = validateObject(errors, data, "/data");
if (validDataObject) {
validateConstantString(errors, data.type, "/data/type", "Message");
validateAttributes(errors, data.attributes);
}
}

if (!isUndefined(data.attributes.personalisation)) {
validateObject(errors, data.attributes.personalisation, "/data/attributes/personalisation")
}
}
}
const validate = () => {
if (parseFailed) return;
if (all) {
var data = all.data;
validateData(errors, data);
}
}

Expand Down
5 changes: 2 additions & 3 deletions proxies/shared/resources/jsc/SetResponseDefaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ try {

if (errorContent) context.setVariable("error.content", JSON.stringify(JSON.parse(errorContent)))
if (responseContent) context.setVariable("response.content", JSON.stringify(JSON.parse(responseContent)))

} catch (e) {
//
} catch (e) { // NOSONAR
// Intentionally ignore parsing errors.
}
Loading