Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ntrnl 546 add static file configuration to use the govuk npm directory #102

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
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ AUTH_SIGN_OUT_URL=${AUTH_PATH}/?logout=true
AWS_ACCESS_KEY_ID=DUMMYIDEXAMPLE
AWS_SECRET_ACCESS_KEY=DUMMYEXAMPLEKEY
BASE_URL=http://localhost:3000
CDN_HOST=test
CDN_HOST="d3ums2fp3imnyp.cloudfront.net"
COOKIE_ID_NAME=github-requests
COOKIE_PARSER_SECRET=test
COOKIE_SESSION_SECRET=test
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,13 @@ The issue is then reviewed by the team, and further comments may be requested if

### Running local development environment with Docker

Docker is used to run the application in **development** mode, with tooling setup to detect changes in local `src` directory and reload the container's node server.
Docker is used to run the application in **development** mode, with tooling setup to detect changes in local `src` directory and reload the container's node server.

- Ensure that `NODE_ENV=development` is set in the `.env` file.

- In order for static assets to be loaded, the `CDN_HOST` must be set to a CDN domain which serves the GOV.UK static assets.

### Building the application

To build the project, run:
To build the project, run:

```sh
make build
Expand Down
43 changes: 0 additions & 43 deletions assets/javascripts/cookies.js

This file was deleted.

7 changes: 5 additions & 2 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ const app = express();

app.disable('x-powered-by');

const assetsPath = path.join(__dirname, '../assets');
app.use('/assets', express.static(assetsPath));
const govukPath = path.join(__dirname, '../node_modules/govuk-frontend/dist/govuk');

app.use('/assets', express.static(`${govukPath}/assets`));
app.use('/govuk-frontend.min.css', express.static(`${govukPath}/govuk-frontend.min.css`));
app.use('/govuk-frontend.min.js', express.static(`${govukPath}/govuk-frontend.min.js`));

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
Expand Down
59 changes: 34 additions & 25 deletions src/config/helmet.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,40 @@
import express from 'express';
import helmet from 'helmet';
import helmet, { HelmetOptions } from 'helmet';

import * as config from '../config';

export const configureHelmet = (app: express.Application) => {
app.use(helmet({
referrerPolicy: {
policy: 'strict-origin-when-cross-origin'
export const HELMET_OPTIONS: HelmetOptions = {
referrerPolicy: {
policy: 'strict-origin-when-cross-origin'
},
contentSecurityPolicy: {
useDefaults: true,
directives: {
defaultSrc: ["'self'"],
fontSrc: ["'self'", config.CDN_HOST],
styleSrc: [
"'self'",
"'unsafe-hashes'",
"'sha256-6FWIojjtZwiNizws7ImlHjGH3DA5yMh5x4c+/4UVpXk='",
config.CDN_HOST
],
scriptSrc: [
"'self'",
"'sha256-pOe+O2hOZnTvxPXzgAfiocCoHgEZxBBgg+a66TylmHw='",
"'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw='",
"'sha256-rDMP7u4Lf+tIufrYmUZIhcf2T3WBD4Pweu0EXe+qaLA='",
"'sha256-wJphCpPdstup3Ojta3HnXJ3EOilATTTWg5oi4S9oi4s='",
config.CDN_HOST
],
imgSrc: ["'self'", 'data:', config.CDN_HOST],
connectSrc: ["'self'"],
formAction: ["'self'"],
objectSrc: ["'none'"]
},
contentSecurityPolicy: {
useDefaults: true,
directives: {
defaultSrc: ["'self'"],
fontSrc: ["'self'", config.CDN_HOST],
styleSrc: ["'self'", "'unsafe-hashes'", "'sha256-6FWIojjtZwiNizws7ImlHjGH3DA5yMh5x4c+/4UVpXk='", config.CDN_HOST],
scriptSrc: [
"'self'",
"'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw='",
"'sha256-rDMP7u4Lf+tIufrYmUZIhcf2T3WBD4Pweu0EXe+qaLA='",
config.CDN_HOST
],
imgSrc: ["'self'", 'data:', config.CDN_HOST],
connectSrc: ["'self'"],
formAction: ["'self'"],
objectSrc: ["'none'"]
},
reportOnly: false
}
}));
reportOnly: false
}
};

export const configureHelmet = (app: express.Application) => {
app.use(helmet(HELMET_OPTIONS));
};
2 changes: 1 addition & 1 deletion src/config/nunjucks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const configureNunjucks = (app: express.Application, viewsPath: string) =
log.info(`Set nunjucks configurations and where nunjucks templates should resolve to: ${viewsPath}`);

const nunjucksEnv = nunjucks.configure(
[viewsPath, 'node_modules/govuk-frontend/dist', 'node_modules/govuk-frontend/dist/components'],
[viewsPath, 'node_modules/govuk-frontend/dist'],
{
autoescape: true,
express: app
Expand Down
13 changes: 6 additions & 7 deletions src/views/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
{% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %}

{% block head %}
<link rel="stylesheet" type="text/css" media="all" href="//{{CDN_HOST}}/govuk-frontend/v5.3.0/govuk-frontend-5.3.0.min.css">
<link rel="stylesheet" type="text/css" media="all" href="/govuk-frontend.min.css">

<link rel="SHORTCUT ICON" href="//{{CDN_HOST}}/images/favicon.ico"/>
<link rel="icon" href="//{{CDN_HOST}}/images/favicon.ico" type="image/x-icon"/>
<link rel="SHORTCUT ICON" href="/assets/images/favicon.ico"/>
<link rel="icon" href="/assets/images/favicon.ico" type="image/x-icon"/>
{% endblock %}

{% block header %}
Expand Down Expand Up @@ -85,11 +85,10 @@

{% block bodyEnd %}
{% if FEATURE_FLAG_ENABLE_COOKIE_BANNER == "true" %}
<script src="/assets/javascripts/cookies.js"></script>
<script src="//{{CDN_HOST}}/app/github-requests-app/javascripts/cookies.js"></script>
{% endif %}
<script type="module" src="//{{CDN_HOST}}/govuk-frontend/v5.3.0/govuk-frontend-5.3.0.min.js"></script>
<script type="module">
import { initAll } from '//{{CDN_HOST}}/govuk-frontend/v5.3.0/govuk-frontend.min.js'
import { initAll } from '/govuk-frontend.min.js'
initAll()
</script>
{% endblock %}
{% endblock %}
25 changes: 0 additions & 25 deletions test/mock/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,31 +98,6 @@ export const MOCK_ERROR = {
message: 'Error message'
} as Error;

export const MOCK_HELMET_VALUE = {
referrerPolicy: {
policy: 'strict-origin-when-cross-origin'
},
contentSecurityPolicy: {
useDefaults: true,
directives: {
defaultSrc: ["'self'"],
fontSrc: ["'self'", config.CDN_HOST],
styleSrc: ["'self'", "'unsafe-hashes'", "'sha256-6FWIojjtZwiNizws7ImlHjGH3DA5yMh5x4c+/4UVpXk='", config.CDN_HOST],
scriptSrc: [
"'self'",
"'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw='",
"'sha256-rDMP7u4Lf+tIufrYmUZIhcf2T3WBD4Pweu0EXe+qaLA='",
config.CDN_HOST
],
imgSrc: ["'self'", 'data:', config.CDN_HOST],
connectSrc: ["'self'"],
formAction: ["'self'"],
objectSrc: ["'none'"]
},
reportOnly: false
}
};

export const MOCK_RATE_LIMIT_VALUE = {
windowMs: 15 * 60 * 1000,
limit: 100,
Expand Down
6 changes: 3 additions & 3 deletions test/unit/config/helmet.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ jest.mock('helmet');
import { describe, expect, test, jest, afterEach } from '@jest/globals';
import helmet from 'helmet';

import { configureHelmet } from '../../../src/config/helmet';
import { MOCK_HELMET_VALUE, MOCK_EXPRESS_APP } from '../../mock/data';
import { configureHelmet, HELMET_OPTIONS } from '../../../src/config/helmet';
import { MOCK_EXPRESS_APP } from '../../mock/data';

describe('Helmet Config test suites', () => {
afterEach(() => {
Expand All @@ -17,7 +17,7 @@ describe('Helmet Config test suites', () => {
configureHelmet(MOCK_EXPRESS_APP);

expect(mockHelmet).toHaveBeenCalledTimes(1);
expect(mockHelmet).toHaveBeenCalledWith(MOCK_HELMET_VALUE);
expect(mockHelmet).toHaveBeenCalledWith(HELMET_OPTIONS);
expect(MOCK_EXPRESS_APP.use).toHaveBeenCalled();
});
});
4 changes: 2 additions & 2 deletions test/unit/config/nunjucks.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
jest.mock('nunjucks');
jest.mock('../../../src/utils/logger');

import { describe, expect, test, jest } from '@jest/globals';
import { describe, expect, afterEach, test, jest } from '@jest/globals';

import * as nunjucks from 'nunjucks';

Expand Down Expand Up @@ -32,7 +32,7 @@ describe('Nunjucks Configuration test suites', () => {
configureNunjucks(MOCK_EXPRESS_APP, MOCK_VIEWS_PATH);

expect(nunjucks.configure).toHaveBeenCalledWith(
[MOCK_VIEWS_PATH, 'node_modules/govuk-frontend/dist', 'node_modules/govuk-frontend/dist/components'],
[MOCK_VIEWS_PATH, 'node_modules/govuk-frontend/dist'],
{
autoescape: true,
express: MOCK_EXPRESS_APP
Expand Down
Loading