Python JavaScript HTML CSS Other
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
.ebextensions config file in .ebextensions to use ELB healthchecks for autoscaling … Jul 11, 2017
.github Fix checkbox in pr template Jul 23, 2018
.tx Internationalisation Working with welsh translation and support for G… Jan 14, 2016
app Update summary.html Aug 16, 2018
data Update guidance on mbs currency fields Aug 16, 2018
database-scripts Re-Work Session Storage Dec 27, 2017
doc/architecture/decisions Added ADR to describe kid value in token headers Jul 13, 2017
gulp Runner to use CDN Mar 9, 2018
jwt-test-keys Logically separate secrets and keys Oct 9, 2017
jwt-test-secrets Logically separate secrets and keys Oct 9, 2017
scripts Refactor metadata structure Jul 30, 2018
tests Hide personal data from page titles Aug 8, 2018
.babelrc implement rollupify Jan 25, 2017
.codecov.yml Ensure Code Covergae in PRs Mar 14, 2018
.coveragerc Setting up Jul 7, 2016
.dockerignore Stop ignoring /static/ folder in Docker builds Oct 10, 2017
.ebignore Updated README Mar 9, 2016
.editorconfig Update various code style config to match Jul 23, 2018
.eslintignore Replace functional with new_functional Oct 24, 2017
.eslintrc Updated client dependencies, Karma + Chrome headless Aug 22, 2017
.gitignore Metadata specified in survey JSON May 30, 2018
.pylintrc Update various code style config to match Jul 23, 2018
.python-version Update builds and instructions to align with AWS ElasticBeanstalk Feb 13, 2017
.stylelintrc Add some stylelint rules Oct 16, 2017
.tern-project Add repeating answers. Nov 22, 2016
.travis.yml Remove CVE ignore now that database has been corrected Aug 2, 2018
.yarnrc implement yarn Nov 1, 2016
Dockerfile Removed `-U` from pip install as they contradict the locked versions Nov 2, 2017
Dockerfile.static Constructed Leaner Dockerfile Jul 28, 2017
LICENSE Update LICENSE Year and Org name May 5, 2017
Pipfile Unpin pytest, fix lockfile issue Aug 1, 2018
Pipfile.lock Unpin pytest, fix lockfile issue Aug 1, 2018 Updated Launcher command in Readme Aug 9, 2018
app-httpd.conf Revert apache log format customisation Mar 10, 2017 move create_app() out of May 24, 2017
babel.cfg completion status incorrectly cleared Jul 6, 2018
docker-compose.yml Updated Launcher command in Readme Aug 9, 2018 Added ability to load schema from url Aug 11, 2017
docker-keys.yml Logically separate secrets and keys Oct 9, 2017
docker-secrets.yml Logically separate secrets and keys Oct 9, 2017
gulpfile.babel.js Set the locale based off of `language_code` in the survey metadata Jul 10, 2018 Logically separate secrets and keys Oct 9, 2017 Logically separate secrets and keys Oct 9, 2017 Logically separate secrets and keys Oct 9, 2017
jsconfig.json added front-end stuff Jan 12, 2016
package.json Refactor metadata structure Jul 30, 2018 Refactor metadata structure Jul 30, 2018
setup.cfg Fixes bug with form showing unrendered schema Jun 5, 2018
tox.ini Re-Work Session Storage Dec 27, 2017
yarn.lock Updates FE dependencies and fixes live reload. May 16, 2018

eQ Survey Runner

Build Status codecov Codacy Badge

Run with Docker

Install Docker for your system:

To get eq-survey-runner running the following command will build and run the containers

docker-compose up -d

To launch a survey, navigate to http://localhost:8000/

When the containers are running you are able to access the application as normal, and code changes will be reflected in the running application. However, any new dependencies that are added would require a re-build.

To rebuild the eq-survey-runner container, the following command can be used.

docker-compose build

If you need to rebuild the container from scratch to re-load any dependencies then you can run the following

docker-compose build --no-cache

To run just the unit tests inside Docker:

docker build -t onsdigital/eq-survey-runner .
docker build -t onsdigital/eq-survey-runner-unit-tests -f Dockerfile.test .
docker run onsdigital/eq-survey-runner-unit-tests

To run the unit tests locally:

pipenv run scripts/


In order to run locally you'll need PostgreSQL and Node.js installed


brew install postgres


brew install npm

Note that npm currently requires Python 2.x for some of the setup steps, it doesn't work with Python 3.


It is preferable to use the version of Python locally that matches that used on deployment. This project has a .python_version file for this purpose.

Upgrade pip and install dependencies:

brew install pyenv
pyenv install
pip install --upgrade pip setuptools pipenv
pipenv install --dev

Run the server inside the virtual env created by Pipenv with:

pipenv run ./scripts/

Note, you will also need to run an upstream tool (eg, to launch a survey.

docker run -e SURVEY_RUNNER_SCHEMA_URL= -it -p 8000:8000 onsdigital/go-launch-a-survey:latest

If you wish to view submitted data you will also need to run an additional upstream tool (eg, to launch a dynamoDB container.

docker run -it -p 6060:8000 onsdigital/eq-docker-dynamodb:latest

This will generate a JWT for you to log into the application.

Front-end Toolkit

The front-end toolkit uses nodejs, yarn and gulp.

Currently, in order to build the front-end toolkit, you will need to have node version 8.X. To do this, do the following commands:

brew install nvm
nvm install 8
nvm use 8

Install yarn with:

npm install yarn --global

Fetch npm dependencies (Note that this overrides the python version defined in .python-version):

PYENV_VERSION=system yarn

Compile the project with

yarn compile

There are a few additional npm tasks:

Command Task
yarn compile Build the assets (js, css, img) into /static
yarn dev Build assets and watch for changes. Runs Browsersync.
yarn test Runs the unit tests through Karma and the functional tests through a local Selenium instance
yarn test_unit Watches the unit tests via Karma
yarn test_functional Runs the functional tests through ChimpJS (requires app running on localhost:5000)
yarn lint Lints the JS, reporting errors/warnings.
yarn format Format the json schemas.

Upgrade usage of the pattern library (Currently) To make an upgrade to the pattern library you'll need to change the short-hand commit hash in the following files:

  • app/assets/favicons/browserconfig.xml <square150x150logo src="[COMMIT HASH HERE]/favicons/mstile-150x150.png"/>
  • app/assets/styles/partials/vars/_vars.scss.xml $cdn-url-root: "[COMMIT HASH HERE]";
  • app/templates/layouts/base.html {% set cdn_hash = "[COMMIT HASH HERE]" %}

Functional test options

To create functional test pages from a schema use the following command. <schema.json> <page_directory>

This can combined with -spec_file=<spec_file_path> to provide a populated template for the functional tests spec file. and/or -require_path='../.. To provide a relative path from a page file to the directory containing the base/parent page classes. Defaults to ".."

For example: ./ ../../data/en/test_navigation.json ./pages/surveys/navigation --spec_file=./spec/navigation.spec.js

The functional tests can be executed with:

yarn test_functional

This can be limited to tests under a directory with:

yarn test_functional --path tests/functional/spec/components/

To run a single test, add @watch into the name of any describe or it function and run:

yarn test_functional --watch

An example of adding @watch looks like this:
describe('@watch Skip Conditions', function() {...} or
it('@watch Given this is a test', function() {...}

To run the tests against a remote deployment you will need to specify the environment variable of EQ_FUNCTIONAL_TEST_ENV eg:

EQ_FUNCTIONAL_TEST_ENV= yarn test_functional

Deployment with elastic beanstalk

You will need to install the EB CLI tools using PIP.

pip install --user awsebcli        # install the eb cli tools

The Elastic Beanstalk CLI requires the presence of a requirements.txt file. To generate one with Pipenv use the following:

pipenv lock -r > requirements.txt

Initialise the project using the command

eb init --region eu-west-1

This will launch a wizard asking for the AWS credentials and some questions about the environment to create.

eu-west-1 is the name for Ireland. I chose the default application name.

Once completed, you can then deploy the application using the following command:

eb create

This will create the environment and spin up the application . Once the application has deployed you can use the following command to open it in a browser

eb open


We use flask-babel to do internationalisation. To extract messages from source, in the project root run the following command.

pybabel extract -F babel.cfg -o app/translations/messages.pot .

This will extract messages and place them in the translations/messages.pot file ready for translation.

You should only need to create the language files once.

To create Welsh language files, run the following command

pybabel init -i app/translations/messages.pot -d app/translations -l cy

To create the gaelic language files, use the following:

pybabel init -i app/translations/messages.pot -d app/translations -l gd

To compile the language files for use in the application, use the following:

pybabel compile -d app/translations

As strings are added to the application, you will need to update but not overwrite the translations for the various languages. To update the language strings, use:

pybabel update -i app/translations/messages.pot -d app/translations

Environment Variables

The following env variables can be used

EQ_USER_AUTHENTICATION_RRM_PUBLIC_KEY - the RRM public key for JWT user authentication
EQ_USER_AUTHENTICATION_SR_PRIVATE_KEY - the SR private key for JWT user authentication
EQ_USER_AUTHENTICATION_SR_PRIVATE_KEY_PASSWORD - password of the SR private key for JWT user authentication
EQ_SUBMISSION_SDX_PUBLIC_KEY - the SDX public key for encryption of Submission data
EQ_SUBMISSION_SR_PRIVATE_SIGNING_KEY - the SR private key for signing of submission data
EQ_SUBMISSION_SR_PRIVATE_SIGNING_KEY_PASSWORD - the password to the SR private key
EQ_RABBITMQ_URL - the RabbitMQ connection string
EQ_RABBITMQ_QUEUE_NAME - the name of the submission queue
EQ_SERVER_SIDE_STORAGE_DATABASE_URL - url of the database to connect to, e.g. 'sqlite:////tmp/questionnaire.db')
EQ_SERVER_SIDE_STORAGE_DATABASE_SETUP_RETRY_COUNT - Number of times to retry setting up the database (connection/creation) if it fails
EQ_SERVER_SIDE_STORAGE_DATABASE_SETUP_RETRY_DELAY_SECONDS - Number of seconds to wait between retry attempts to setup the database
EQ_LOG_LEVEL - The default logging level (defaults to 'INFO' for local development)
EQ_WERKZEUG_LOG_LEVEL - The default logging level for werkzeug (defaults to 'INFO' for local development)
EQ_SCHEMA_DIRECTORY - The directory that contains the schema files
EQ_SESSION_TIMEOUT_SECONDS - The duration of the flask session
EQ_SESSION_TIMEOUT_GRACE_PERIOD_SECONDS - The grace period between when the server removes the session and what we tell the client
EQ_SECRET_KEY - The Flask secret key for signing cookies
EQ_PROFILING - Enables or disables profiling (True/False) Default False/Disabled
EQ_UA_ID - The Google Analytics ID
EQ_SCHEMA_BUCKET - The name of the bucket in S3 where to look to find schemas
SAUCE_USERNAME - Sauce Labs username
SAUCE_ACCESS_KEY - Sauce Labs private key
EQ_DEV_MODE - Enable dev mode
EQ_ENABLE_FLASK_DEBUG_TOOLBAR - Enable the flask debug toolbar
EQ_ENABLE_CACHE - Enable caching of the schema
EQ_ENABLE_SECURE_SESSION_COOKIE - Set secure session cookies
EQ_MAX_HTTP_POST_CONTENT_LENGTH - The maximum http post content length that the system wil accept
EQ_MAX_NUM_REPEATS - The maximum number of repeats the system will allow
EQ_DEVELOPER_LOGGING - Enable developer style logging described here
EQ_ENABLE_LIVE_RELOAD - Enable livereload of browser when scripts, styles or templates are updated

EQ_NEW_RELIC_ENABLED - Enable New Relic monitoring
NEW_RELIC_LICENSE_KEY - Enable new relic monitoring by supplying a New Relic licence key
NEW_RELIC_APP_NAME - The name to display for the application in New Relic

The following env variables can be used when running tests

EQ_FUNCTIONAL_TEST_ENV - the pre-configured environment [local, docker, preprod] or the url of the environment that should be targeted

JWT Integration

Integration with the survey runner requires the use of a signed JWT using public and private key pair (see,,

Once signed the JWT must be encrypted using JWE (see

The JWT payload must contain the following claims:

  • exp - expiration time
  • iat - issued at time

The header of the JWT must include the following:

  • alg - the signing algorithm (must be RS256)
  • type - the token type (must be JWT)
  • kid - key identification (must be EDCRRM)

The JOSE header of the final JWE must include:

  • alg - the key encryption algorithm (must be RSA-OAEP)
  • enc - the key encryption encoding (must be A256GCM)

To access the application you must provide a valid JWT. To do this browse to the /session url and append a token parameter. This parameter must be set to a valid JWE encrypted JWT token. Only encrypted tokens are allowed.

There is a python script for generating tokens for use in development, to run:



Setting the EQ_PROFILING environment variable to True will enable profiling of the application. Profiling information will be collected per-request in the profiling directory where it can be examined using the Pstats Interactive Browser.

$ python -m pstats <filename>

will load the file into the interactive browser where it can be sorted and queried as required.

Updating / Installing dependencies

We make use of Python pip's support for only installing packages if their sha-256 hash matches a known good value.

To add a new dependency, use pipenv install [package-name], which not only installs the package but Pipenv will also go to the trouble of updating the Pipfile as well.

NB: both the Pipfile and Pipfile.lock files are required in source control to accurately pin dependencies.

Alpha Survey Runner

If you're looking for the Survey Runner code from the Alpha then it has been renamed to: alpha-eq-survey-runner