Skip to content

Taking the GOVUK flask frontend skeleton and making it more open (Removing environmental and security locks)

Notifications You must be signed in to change notification settings

ministryofjustice/moj-flask-govuk-skeleton

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MOJ GOV.UK Frontend Flask

This is a clone from the HM Land Registery Flask skeleton GOV.UK Frontend Flask. Thank you, Land Registry.

govuk-frontend 5.7.1

GOV.UK Frontend Flask is a community tool of the GOV.UK Design System. The Design System team is not responsible for it and cannot support you with using it. Contact the maintainers directly if you need help or you want to request a feature.

This is a template Flask app using the GOV.UK Frontend and GOV.UK Design System which is designed to get a new project started quicker. It is also a reference implementation of two core packages:

The app is provided intentionally bare, with just the essential parts that all services need, such as error pages, accessibility statement, cookie banner, cookie page and privacy notice. It uses a number of other packages to provide the features described below with sensible and best-practice defaults. Please read the next steps section for guidance on how to start building out your app on top of this template.

Versioning

  • Python: 3.12
  • Node.js: 22.12.0
  • npm: 10.9.0
  • pip: 24.3.1

Getting started

Local install for development:

Setup

Create a virtual environment and install the python dependencies:

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.in -r requirements_dev.in

Note on dependencies:

  • requirements.in are the direct dependencies of the app.
  • requirements_dev.in are the dependencies needed only during development - linters, code formatting etc
  • (requirements*.txt - in a production system we'd generate a .txt from each .in file. The .txt file includes all direct dependencies in the .in, plus their dependencies too (indirect dependencies). And all dependencies have their exact version specified ('pinned'). This ensures production environment installs exactly the same as the test environment and what developers install.)

Assets setup

This project uses Node.js to manage assets and handle other Node.js-related tasks.

To get started, ensure you have NVM installed on your machine.

This project includes an .nvmrc file, making it easy to set up the correct Node.js version.

Follow these commands to configure your environment:

nvm install
nvm use
node -v

Now that Node is installed

npm install

Once installed you now have access to GOVUK components, stylesheets and JS via the node_module

To copy some of the assets you'll need into your project, run the following:

npm run build

Ensure you do this before starting your Flask project as you're JS and SCSS imports will fail in the flask run.

Demo assets

For the demo of the MOJ Flask Skeleton, you'll need the govuk_components yaml files.

./build.sh

You will not need this in your development project. This is only for the MOJ Flask Skeleton Demo.

Configuration environment variables

Create your local config file .env from the template file:

cp .env.example .env

Don't worry, you can't commit your .env file.

Run the service

source .venv/bin/activate
flask --app app run --debug --port=8000

Now you can browse: http://127.0.0.1:8000

(The default port for flask apps is 5000, but on Macs this is often found to conflict with Apple's Airplay service, hence using another port here.)

Running in Docker

For local development and deployments, run the below code:

./run_local.sh

Set local Docker environment variables

In the compose.yml file you will find a number of environment variables. These are injected as global variables into the app and pre-populated into page templates as appropriate. Enter your specific service information for the following:

  • CONTACT_EMAIL
  • CONTACT_PHONE
  • DEPARTMENT_NAME
  • DEPARTMENT_URL
  • SERVICE_NAME
  • SERVICE_PHASE
  • SERVICE_URL

You must also set a new unique SECRET_KEY, which is used to securely sign the session cookie and CSRF tokens. It should be a long random bytes or str. You can use the output of this Python comand to generate a new key:

python -c 'import secrets; print(secrets.token_hex())'

Run containers

docker compose up --build

Demos

There are some helpful demos included by default that show all of the components available from GOV.UK Frontend Jinja and a selection of forms and validation patterns from GOV.UK Frontend WTForms. These are located in the app/demos and app/templates/demos directories, along with the demos blueprint. Use them for reference whilst building your service, but make sure to delete them, along with the relevant section in build.sh, before deploying the app.

Testing

To run the tests:

python -m pytest --cov=app --cov-report=term-missing --cov-branch

Playwright Testing

To run tests:

pytest

Run tests in headed mode:

pytest --headed

Run tests in a different browser (chromium, firefox, webkit):

pytest --browser firefox

Run tests in multiple browsers:

pytest --browser chromium --browser webkit

If you are running into issues where it states a browser needs to be installed run:

playwright install

For further guidance on writing tests https://playwright.dev/python/docs/writing-tests

Code formatting and linting

The Flake8 linter looks for code quality issues. Ensure there are no flake8 issues before committing. To run it:

flake8

All code should be formatted with black and isort before committing. To run them:

black .
isort .

Features

Please refer to the specific packages documentation for more details.

Asset management

Custom CSS and JavaScript files are merged and compressed using Flask Assets and Webassets. This takes all *.css files in app/static/src/css and all *.js files in app/static/src/js and outputs a single compressed file to both app/static/dist/css and app/static/dist/js respectively.

CSS is minified using CSSMin and JavaScript is minified using JSMin. This removes all whitespace characters, comments and line breaks to reduce the size of the source code, making its transmission over a network more efficient.

Flask-Assets provides a built-in cache system to improve performance by caching compiled assets. However, this can sometimes lead to issues where changes to your source files are not immediately reflected in the compiled output.

Flask-Assets uses ASSETS_MANIFEST which enables the cache manifest feature. Flask-Assets will generate a cache manifest file containing the paths to the compiled asset files. These are used to help with the hashing on generated asset files.

Note: When you start developing with Flask, you'll see a directory appear app/static/webasset-cache. webassets-cache stores the asset manifest. If for some reason Flask-Assets is not picking up your changes to files, clear the folder of its caches.

Cache busting

Merged and compressed assets are browser cache busted on update by modifying their URL with their MD5 hash using Flask Assets and Webassets. The MD5 hash is appended to the file name, for example custom-d41d8cd9.css instead of a query string, to support certain older browsers and proxies that ignore the querystring in their caching behaviour.

Forms generation and validation

Uses Flask WTF and WTForms to define and validate forms. Forms are rendered in your template using regular Jinja syntax.

Form error handling

If a submitted form has any validation errors, an error summary component is shown at the top of the page, along with individual field error messages. This follows the GOV.UK Design System validation pattern and is built into the base page template.

Flash messages

Messages created with Flask's flash function will be rendered using the GOV.UK Design System notification banner component. By default the blue "important" banner style will be used, unless a category of "success" is passed to use the green version.

CSRF protection

Uses Flask WTF to enable Cross Site Request Forgery protection per form and for the whole app.

CSRF errors are handled by creating a flash message notification banner to inform the user that the form they submitted has expired.

HTTP security headers

Uses Flask Talisman to set HTTP headers that can help protect against a few common web application security issues.

  • Forces all connections to https, unless running with debug enabled.
  • Enables HTTP Strict Transport Security.
  • Sets Flask's session cookie to secure, so it will never be set if your application is somehow accessed via a non-secure connection.
  • Sets Flask's session cookie to httponly, preventing JavaScript from being able to access its content.
  • Sets X-Frame-Options to SAMEORIGIN to avoid clickjacking.
  • Sets X-XSS-Protection to enable a cross site scripting filter for IE and Safari (note Chrome has removed this and Firefox never supported it).
  • Sets X-Content-Type-Options to prevent content type sniffing.
  • Sets a strict Referrer-Policy of strict-origin-when-cross-origin that governs which referrer information should be included with requests made.

Content Security Policy

A strict default Content Security Policy (CSP) is set using Flask Talisman to mitigate Cross Site Scripting (XSS) and packet sniffing attacks. This prevents loading any resources that are not in the same domain as the application.

Response compression

Uses Flask Compress to compress response data. This inspects the Accept-Encoding request header, compresses using either gzip, deflate or brotli algorithms and sets the Content-Encoding response header. HTML, CSS, XML, JSON and JavaScript MIME types will all be compressed.

Rate limiting

Uses Flask Limiter to set request rate limits on routes. The default rate limit is 2 requests per second and 60 requests per minute (whichever is hit first) based on the client's remote IP address. Every time a request exceeds the rate limit, the view function will not get called and instead a HTTP 429 status will be returned.

Rate limit storage can be backed by Redis using the RATELIMIT_STORAGE_URL config value in config.py, or fall back to in-memory if not present. Rate limit information will also be added to various response headers.

Otherwise, please see the contribution guidelines for how to raise a bug report or feature request.

About

Taking the GOVUK flask frontend skeleton and making it more open (Removing environmental and security locks)

Resources

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published