mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-24 08:16:51 -04:00
Merge pull request #30 from GSA/security-scans
Add security & compliance scans
This commit is contained in:
18
.github/actions/setup-project/action.yml
vendored
Normal file
18
.github/actions/setup-project/action.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Set up project
|
||||
description: Setup python & install dependencies
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install container dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update \
|
||||
&& sudo apt-get install -y --no-install-recommends \
|
||||
libcurl4-openssl-dev
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.9"
|
||||
- name: Install application dependencies
|
||||
shell: bash
|
||||
run: make bootstrap
|
||||
68
.github/workflows/checks.yml
vendored
68
.github/workflows/checks.yml
vendored
@@ -29,20 +29,9 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Install container dependencies
|
||||
run: |
|
||||
sudo apt-get update \
|
||||
&& sudo apt-get install -y --no-install-recommends \
|
||||
libcurl4-openssl-dev
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.9"
|
||||
- name: Install application dependencies
|
||||
run: make bootstrap
|
||||
- uses: ./.github/actions/setup-project
|
||||
- name: Run style checks
|
||||
run: flake8 .
|
||||
- name: Check imports alphabetized
|
||||
@@ -51,3 +40,58 @@ jobs:
|
||||
run: npm test
|
||||
- name: Run py tests
|
||||
run: pytest -n4 --maxfail=10
|
||||
|
||||
dependency-audits:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup-project
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
with:
|
||||
inputs: requirements.txt requirements_for_test.txt
|
||||
ignore-vulns: PYSEC-2022-237
|
||||
- name: Run npm audit
|
||||
run: make npm-audit
|
||||
|
||||
static-scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup-project
|
||||
- name: Install bandit
|
||||
run: pip install bandit
|
||||
- name: Run scan
|
||||
run: bandit -r app/ --confidence-level medium
|
||||
|
||||
dynamic-scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup-project
|
||||
- name: Run server
|
||||
run: make run-flask &
|
||||
env:
|
||||
NOTIFY_ENVIRONMENT: scanning
|
||||
- name: Run OWASP Baseline Scan
|
||||
uses: zaproxy/action-baseline@v0.7.0
|
||||
with:
|
||||
docker_name: 'owasp/zap2docker-weekly'
|
||||
target: 'http://localhost:6012'
|
||||
fail_action: true
|
||||
allow_issue_writing: false
|
||||
rules_file_name: 'zap.conf'
|
||||
cmd_options: '-I'
|
||||
|
||||
a11y-scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup-project
|
||||
- name: Run server
|
||||
run: make run-flask &
|
||||
env:
|
||||
NOTIFY_ENVIRONMENT: scanning
|
||||
- name: Install pa11y-ci
|
||||
run: npm install -g pa11y-ci
|
||||
- name: Run pa11y-ci
|
||||
run: pa11y-ci
|
||||
|
||||
73
.github/workflows/daily_checks.yml
vendored
Normal file
73
.github/workflows/daily_checks.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
name: Run daily scans
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# cron format: 'minute hour dayofmonth month dayofweek'
|
||||
# this will run at 10am UTC every day (5am EST / 6am EDT)
|
||||
- cron: '0 10 * * *'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
NOTIFY_ENVIRONMENT: test
|
||||
FLASK_APP: application.py
|
||||
FLASK_ENV: development
|
||||
WERKZEUG_DEBUG_PIN: off
|
||||
REDIS_URL: redis://adminredis:6379/0
|
||||
DEV_REDIS_URL: redis://adminredis:6379/0
|
||||
REDIS_ENABLED: False
|
||||
ANTIVIRUS_ENABLED: 0
|
||||
NODE_VERSION: 16.15.1
|
||||
ADMIN_CLIENT_ID: notify-admin
|
||||
ADMIN_CLIENT_USERNAME: notify-admin
|
||||
ADMIN_CLIENT_SECRET: dev-notify-secret-key
|
||||
GOVUK_ALERTS_CLIENT_ID: govuk-alerts
|
||||
ADMIN_BASE_URL: http://localhost:6012
|
||||
API_HOST_NAME: http://localhost:6011
|
||||
DEV_API_HOST_NAME: http://localhost:6011
|
||||
AWS_REGION: us-west-2
|
||||
BASIC_AUTH_USERNAME: curiousabout
|
||||
BASIC_AUTH_PASSWORD: the10xnotifybeta
|
||||
|
||||
jobs:
|
||||
dependency-audits:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup-project
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
with:
|
||||
inputs: requirements.txt requirements_for_test.txt
|
||||
ignore-vulns: PYSEC-2022-237
|
||||
- name: Run npm audit
|
||||
run: make npm-audit
|
||||
|
||||
static-scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup-project
|
||||
- name: Install bandit
|
||||
run: pip install bandit
|
||||
- name: Run scan
|
||||
run: bandit -r app/ --confidence-level medium
|
||||
|
||||
dynamic-scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup-project
|
||||
- name: Run server
|
||||
run: make run-flask &
|
||||
env:
|
||||
NOTIFY_ENVIRONMENT: scanning
|
||||
- name: Run OWASP Full Scan
|
||||
uses: zaproxy/action-full-scan@v0.4.0
|
||||
with:
|
||||
docker_name: 'owasp/zap2docker-weekly'
|
||||
target: 'http://localhost:6012'
|
||||
fail_action: true
|
||||
allow_issue_writing: false
|
||||
rules_file_name: 'zap.conf'
|
||||
cmd_options: '-I'
|
||||
20
.pa11yci
Normal file
20
.pa11yci
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"defaults": {
|
||||
"standard": "WCAG2AA",
|
||||
"runners": ["axe"],
|
||||
"hideElements": [
|
||||
"nav > ol a",
|
||||
"iframe[src^=\"https://www.youtube\"]",
|
||||
"#sms-pricing-details",
|
||||
"a.govuk-footer__link.govuk-footer__copyright-logo"
|
||||
]
|
||||
},
|
||||
"urls": [
|
||||
"http://localhost:6012",
|
||||
"http://localhost:6012/support",
|
||||
"http://localhost:6012/features",
|
||||
"http://localhost:6012/pricing",
|
||||
"http://localhost:6012/documentation",
|
||||
"http://localhost:6012/sign-in"
|
||||
]
|
||||
}
|
||||
18
Makefile
18
Makefile
@@ -73,6 +73,24 @@ freeze-requirements: ## create static requirements.txt
|
||||
${VIRTUALENV_ROOT}/bin/pip install --upgrade pip-tools
|
||||
${VIRTUALENV_ROOT}/bin/pip-compile requirements.in
|
||||
|
||||
.PHONY: pip-audit
|
||||
pip-audit:
|
||||
pip install --upgrade pip-audit
|
||||
pip-audit -r requirements.txt -r requirements_for_test.txt -l --ignore-vuln PYSEC-2022-237
|
||||
|
||||
.PHONY: audit
|
||||
audit: npm-audit pip-audit
|
||||
|
||||
.PHONY: static-scan
|
||||
static-scan:
|
||||
pip install bandit
|
||||
bandit -r app/
|
||||
|
||||
.PHONY: a11y-scan
|
||||
a11y-scan:
|
||||
npm install -g pa11y-ci
|
||||
pa11y-ci
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf node_modules cache target ${CF_MANIFEST_PATH}
|
||||
|
||||
@@ -18,7 +18,7 @@ Open the notifications-admin repo in VS Code (File->Open Folder, select notifica
|
||||
|
||||
create a .env file as detailed in the .env Setup section below
|
||||
|
||||
Using VS Code's command pallette (cmd+shift+p), search "Remote Containers: Open folder in Container..."
|
||||
Using VS Code's command pallette (cmd+shift+p), search "Remote Containers: Open folder in Container..."
|
||||
|
||||
choose devcontainer-admin folder (note: this is a subfolder of notifications-admin/). This will open a new window, closing the current one in the process. After the new window loads, hit "show logs" link in the bottom-right. If this is the first build it will take a few minutes to create the image. The process completes shortly after running gulp.js and compiling front-end files.
|
||||
|
||||
@@ -52,6 +52,13 @@ npm run test-watch
|
||||
|
||||
To run a specific JavaScript test, you'll need to copy the full command from `package.json`.
|
||||
|
||||
## Running a11y-scans locally
|
||||
|
||||
Unlike most of the tests and scans, pa11y-ci cannot currently be run from within the VSCode dev container.
|
||||
|
||||
1. Run `make run-flask` from within the devcontainer
|
||||
2. Run `make a11y-scan` from your host computer.
|
||||
|
||||
## Further docs [STILL UK DOCS]
|
||||
|
||||
- [Working with static assets](docs/static-assets.md)
|
||||
|
||||
@@ -37,7 +37,7 @@ class AssetFingerprinter(object):
|
||||
return self._cache[asset_path]
|
||||
|
||||
def get_asset_fingerprint(self, asset_file_path):
|
||||
return hashlib.md5(
|
||||
return hashlib.md5( # nosec B324 - hash value is not verified, so md5 is fine
|
||||
self.get_asset_file_contents(asset_file_path)
|
||||
).hexdigest()
|
||||
|
||||
|
||||
@@ -21,17 +21,29 @@ $button-shadow-size: $govuk-border-width-form-element;
|
||||
user-select: none;
|
||||
padding: 0 0 govuk-spacing(9) 0;
|
||||
|
||||
.govuk-grid-column-one-third {
|
||||
display: none;
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@include media(desktop) {
|
||||
background-image: file-url('product/proposition-illustration.png');
|
||||
background-size: 320px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right -6px top 100px;
|
||||
.govuk-grid-column-one-third {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&--alternative {
|
||||
@include media(desktop) {
|
||||
background-image: file-url('product/proposition-alternative.svg');
|
||||
background-size: 320px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 10px bottom 0;
|
||||
|
||||
.govuk-grid-column-one-third {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import csv
|
||||
import pickle
|
||||
import sys
|
||||
from math import isclose
|
||||
from pathlib import Path
|
||||
from pickle import dumps # nosec B403
|
||||
|
||||
import geojson
|
||||
from notifications_utils.formatters import formatted_list
|
||||
@@ -104,8 +104,10 @@ def clean_up_invalid_polygons(polygons, indent=" "):
|
||||
|
||||
# Make sure the polygon is now valid, and that we haven’t
|
||||
# drastically transformed the polygon by ‘fixing’ it
|
||||
assert fixed_polygon.is_valid
|
||||
assert isclose(fixed_polygon.area, shapely_polygon.area, rel_tol=0.001)
|
||||
if not fixed_polygon.is_valid:
|
||||
raise RuntimeError("Fixed polygon is no longer valid")
|
||||
if not isclose(fixed_polygon.area, shapely_polygon.area, rel_tol=0.001):
|
||||
raise RuntimeError("Fixed polygon moved too much")
|
||||
|
||||
print( # noqa: T201
|
||||
f"{indent}Polygon {index + 1}/{len(polygons)} fixed!"
|
||||
@@ -158,7 +160,8 @@ def polygons_and_simplified_polygons(feature):
|
||||
# Check that the simplification process hasn’t introduced bad data
|
||||
for dataset in output:
|
||||
for polygon in dataset:
|
||||
assert Polygon(polygon).is_valid
|
||||
if not Polygon(polygon).is_valid:
|
||||
raise RuntimeError('Simplification process introduced bad data')
|
||||
|
||||
return output + [simplified.utm_crs]
|
||||
|
||||
@@ -360,7 +363,7 @@ def _add_electoral_wards(dataset_id):
|
||||
except KeyError:
|
||||
print("Skipping", ward_code, ward_name) # noqa: T201
|
||||
|
||||
rtree_index_path.open('wb').write(pickle.dumps(rtree_index))
|
||||
rtree_index_path.open('wb').write(dumps(rtree_index))
|
||||
repo.insert_broadcast_areas(areas_to_add, keep_old_polygons)
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import json
|
||||
import os
|
||||
import pickle
|
||||
import pickle # nosec B403 - loads only used with trusted input
|
||||
import sqlite3
|
||||
from json import dumps, loads
|
||||
from pathlib import Path
|
||||
|
||||
rtree_index_path = Path(__file__).parent / 'rtree.pickle'
|
||||
rtree_index = pickle.loads(rtree_index_path.read_bytes())
|
||||
rtree_index = pickle.loads(rtree_index_path.read_bytes()) # nosec B301 - trusted input
|
||||
|
||||
|
||||
class BroadcastAreasRepository(object):
|
||||
@@ -111,7 +111,7 @@ class BroadcastAreasRepository(object):
|
||||
))
|
||||
if not keep_old_features:
|
||||
conn.execute(features_q, (
|
||||
id, json.dumps(polygons), json.dumps(simple_polygons), utm_crs
|
||||
id, dumps(polygons), dumps(simple_polygons), utm_crs
|
||||
))
|
||||
|
||||
def query(self, sql, *args):
|
||||
@@ -127,13 +127,10 @@ class BroadcastAreasRepository(object):
|
||||
return sorted(libraries)
|
||||
|
||||
def get_areas(self, area_ids):
|
||||
q = """
|
||||
SELECT id, name, count_of_phones, broadcast_area_library_id
|
||||
FROM broadcast_areas
|
||||
WHERE id IN ({})
|
||||
""".format(",".join("?" * len(area_ids)))
|
||||
q = "SELECT id, name, count_of_phones, broadcast_area_library_id FROM broadcast_areas"
|
||||
where = "WHERE id IN ({})".format(",".join("?" * len(area_ids)))
|
||||
|
||||
results = self.query(q, *area_ids)
|
||||
results = self.query(F"{q} {where}", *area_ids)
|
||||
|
||||
areas = [
|
||||
(row[0], row[1], row[2], row[3])
|
||||
@@ -147,13 +144,13 @@ class BroadcastAreasRepository(object):
|
||||
SELECT broadcast_areas.id, name, count_of_phones, broadcast_area_library_id, simple_polygons, utm_crs
|
||||
FROM broadcast_areas
|
||||
JOIN broadcast_area_polygons on broadcast_area_polygons.id = broadcast_areas.id
|
||||
WHERE broadcast_areas.id IN ({})
|
||||
""".format(",".join("?" * len(area_ids)))
|
||||
"""
|
||||
where = "WHERE broadcast_areas.id IN ({})".format(",".join("?" * len(area_ids)))
|
||||
|
||||
results = self.query(q, *area_ids)
|
||||
results = self.query(F"{q} {where}", *area_ids)
|
||||
|
||||
areas = [
|
||||
(row[0], row[1], row[2], row[3], json.loads(row[4]), row[5])
|
||||
(row[0], row[1], row[2], row[3], loads(row[4]), row[5])
|
||||
for row in results
|
||||
]
|
||||
|
||||
@@ -239,7 +236,7 @@ class BroadcastAreasRepository(object):
|
||||
|
||||
results = self.query(q, area_id)
|
||||
|
||||
return json.loads(results[0][0]), results[0][1]
|
||||
return loads(results[0][0]), results[0][1]
|
||||
|
||||
def get_simple_polygons_for_area(self, area_id):
|
||||
q = """
|
||||
@@ -250,4 +247,4 @@ class BroadcastAreasRepository(object):
|
||||
|
||||
results = self.query(q, area_id)
|
||||
|
||||
return json.loads(results[0][0]), results[0][1]
|
||||
return loads(results[0][0]), results[0][1]
|
||||
|
||||
@@ -102,7 +102,7 @@ class Config(object):
|
||||
|
||||
class Development(Config):
|
||||
ADMIN_BASE_URL = 'http://localhost:6012'
|
||||
BASIC_AUTH_FORCE = True
|
||||
BASIC_AUTH_FORCE = False
|
||||
NOTIFY_LOG_PATH = 'application.log'
|
||||
DEBUG = True
|
||||
SESSION_COOKIE_SECURE = False
|
||||
@@ -120,7 +120,7 @@ class Development(Config):
|
||||
# check for local compose orchestration variable
|
||||
API_HOST_NAME = os.environ.get('DEV_API_HOST_NAME', 'http://dev:6011')
|
||||
DANGEROUS_SALT = 'dev-notify-salt'
|
||||
SECRET_KEY = 'dev-notify-secret-key'
|
||||
SECRET_KEY = 'dev-notify-secret-key' # nosec B105 - only used in development
|
||||
ANTIVIRUS_API_HOST = 'http://localhost:6016'
|
||||
ANTIVIRUS_API_KEY = 'test-key'
|
||||
ANTIVIRUS_ENABLED = os.environ.get('ANTIVIRUS_ENABLED') == '1'
|
||||
@@ -156,6 +156,14 @@ class Test(Development):
|
||||
ASSET_PATH = 'https://static.example.com/'
|
||||
|
||||
|
||||
class Scanning(Test):
|
||||
BASIC_AUTH_FORCE = False
|
||||
API_HOST_NAME = 'https://notifications-api.app.cloud.gov/'
|
||||
NOTIFY_ENVIRONMENT = 'scanning'
|
||||
ASSET_DOMAIN = ''
|
||||
ASSET_PATH = '/static/'
|
||||
|
||||
|
||||
class Preview(Config):
|
||||
BASIC_AUTH_FORCE = True
|
||||
HTTP_PROTOCOL = 'https'
|
||||
@@ -242,6 +250,7 @@ class Sandbox(CloudFoundryConfig):
|
||||
configs = {
|
||||
'development': Development,
|
||||
'test': Test,
|
||||
'scanning': Scanning,
|
||||
'preview': Preview,
|
||||
'staging': Staging,
|
||||
'live': Live,
|
||||
|
||||
@@ -25,7 +25,7 @@ from app.notify_client.api_key_api_client import (
|
||||
)
|
||||
from app.utils.user import user_has_permissions
|
||||
|
||||
dummy_bearer_token = 'bearer_token_set'
|
||||
dummy_bearer_token = 'bearer_token_set' # nosec B105 - this is not a real token
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/api")
|
||||
|
||||
@@ -31,7 +31,7 @@ from app.utils.user import user_is_gov_user, user_is_logged_in
|
||||
|
||||
NEW_EMAIL = 'new-email'
|
||||
NEW_MOBILE = 'new-mob'
|
||||
NEW_MOBILE_PASSWORD_CONFIRMED = 'new-mob-password-confirmed'
|
||||
NEW_MOBILE_PASSWORD_CONFIRMED = 'new-mob-password-confirmed' # nosec B105 - this is not a password
|
||||
|
||||
|
||||
@main.route("/user-profile")
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -225,6 +225,7 @@
|
||||
|
||||
{{ govukDetails({
|
||||
"summaryText": "International text message rates",
|
||||
"id": "sms-pricing-details",
|
||||
"html": smsIntRates
|
||||
}) }}
|
||||
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
it before
|
||||
</div>
|
||||
</div>
|
||||
<div class="govuk-grid-column-one-third">
|
||||
<img
|
||||
src="{{ asset_url('images/product/proposition-illustration.png') }}"
|
||||
alt="An illustration of notifications to a phone, a laptop, and a letter.">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -58,7 +63,9 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="govuk-grid-column-one-half">
|
||||
<img src="{{ asset_url('images/product/01-templates.svg') }}" alt="">
|
||||
<img
|
||||
src="{{ asset_url('images/product/01-templates.svg') }}"
|
||||
alt="Example screenshot of adding a new text message template">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -114,7 +121,7 @@
|
||||
</h2>
|
||||
<div class="responsive-embed responsive-embed--16by9 responsive-embed--bordered bottom-gutter-2">
|
||||
<div class="responsive-embed__wrapper">
|
||||
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/_90cv1YgQo4" frameborder="0" allowfullscreen></iframe>
|
||||
<iframe title="US Notify introduction video" width="560" height="315" src="https://www.youtube-nocookie.com/embed/_90cv1YgQo4" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -125,12 +132,12 @@
|
||||
<div class="govuk-grid-column-one-half">
|
||||
<span class="govuk-visually-hidden">There are</span>
|
||||
<div class="product-page-big-number">{{ counts.organisations|format_thousands }}</div>
|
||||
organisations
|
||||
<span>organisations</span>
|
||||
</div>
|
||||
<div class="govuk-grid-column-one-half">
|
||||
<span class="govuk-visually-hidden">and</span>
|
||||
<div class="product-page-big-number">{{ counts.services|format_thousands }}</div>
|
||||
services
|
||||
<span>services</span>
|
||||
<span class="govuk-visually-hidden">using Notify.</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -147,18 +154,18 @@
|
||||
<div class="govuk-grid-column-one-half">
|
||||
<h3 class="govuk-visually-hidden">Emails</h3>
|
||||
<div class="product-page-big-number">Unlimited</div>
|
||||
free emails
|
||||
<span>free emails</span>
|
||||
</div>
|
||||
<div class="govuk-grid-column-one-half">
|
||||
<h3 class="govuk-visually-hidden">Text messages</h3>
|
||||
<div class="product-page-big-number">Up to 40,000</div>
|
||||
free text messages a year,<br>
|
||||
then {{ sms_rate }} pence per message
|
||||
<span>free text messages a year,<br>
|
||||
then {{ sms_rate }} pence per message</span>
|
||||
</div>
|
||||
<div class="govuk-grid-column-one-half">
|
||||
<h3 class="govuk-visually-hidden">Letters</h3>
|
||||
<div class="product-page-big-number">41 pence</div>
|
||||
to print and post a one page letter
|
||||
<span>to print and post a one page letter</span>
|
||||
</div>
|
||||
<div class="govuk-grid-column-one-half">
|
||||
<p class="align-with-big-number-hint">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"test-watch": "jest --watch --config tests/javascripts/jest.config.js tests/javascripts",
|
||||
"build": "gulp",
|
||||
"watch": "gulp watch",
|
||||
"audit": "better-npm-audit audit --production --level high"
|
||||
"audit": "better-npm-audit audit --production --level low"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
121
zap.conf
Normal file
121
zap.conf
Normal file
@@ -0,0 +1,121 @@
|
||||
# zap-full-scan rule configuration file
|
||||
# Change WARN to IGNORE to ignore rule or FAIL to fail if rule matches
|
||||
# Active scan rules set to IGNORE will not be run which will speed up the scan
|
||||
# Only the rule identifiers are used - the names are just for info
|
||||
# You can add your own messages to each rule by appending them after a tab on each line.
|
||||
0 WARN (Directory Browsing - Active/release)
|
||||
10003 WARN (Vulnerable JS Library - Passive/release)
|
||||
10010 FAIL (Cookie No HttpOnly Flag - Passive/release)
|
||||
10011 FAIL (Cookie Without Secure Flag - Passive/release)
|
||||
10015 WARN (Incomplete or No Cache-control Header Set - Passive/release)
|
||||
10016 FAIL (Web Browser XSS Protection Not Enabled)
|
||||
10017 WARN (Cross-Domain JavaScript Source File Inclusion - Passive/release)
|
||||
10019 WARN (Content-Type Header Missing - Passive/release)
|
||||
10020 FAIL (X-Frame-Options Header - Passive/release)
|
||||
10021 WARN (X-Content-Type-Options Header Missing - Passive/release)
|
||||
10023 WARN (Information Disclosure - Debug Error Messages - Passive/release)
|
||||
10024 FAIL (Information Disclosure - Sensitive Information in URL - Passive/release)
|
||||
10025 FAIL (Information Disclosure - Sensitive Information in HTTP Referrer Header - Passive/release)
|
||||
10026 WARN (HTTP Parameter Override - Passive/beta)
|
||||
10027 WARN (Information Disclosure - Suspicious Comments - Passive/release)
|
||||
10028 FAIL (Open Redirect - Passive/beta)
|
||||
10029 WARN (Cookie Poisoning - Passive/beta)
|
||||
10030 WARN (User Controllable Charset - Passive/beta)
|
||||
10031 WARN (User Controllable HTML Element Attribute (Potential XSS) - Passive/beta)
|
||||
10032 WARN (Viewstate - Passive/release)
|
||||
10033 WARN (Directory Browsing - Passive/beta)
|
||||
10034 WARN (Heartbleed OpenSSL Vulnerability (Indicative) - Passive/beta)
|
||||
10035 FAIL (Strict-Transport-Security Header - Passive/beta)
|
||||
10036 WARN (HTTP Server Response Header - Passive/beta)
|
||||
10037 WARN (Server Leaks Information via "X-Powered-By" HTTP Response Header Field(s) - Passive/release)
|
||||
10038 FAIL (Content Security Policy (CSP) Header Not Set - Passive/beta)
|
||||
10039 WARN (X-Backend-Server Header Information Leak - Passive/beta)
|
||||
10040 FAIL (Secure Pages Include Mixed Content - Passive/release)
|
||||
10041 WARN (HTTP to HTTPS Insecure Transition in Form Post - Passive/beta)
|
||||
10042 WARN (HTTPS to HTTP Insecure Transition in Form Post - Passive/beta)
|
||||
10043 FAIL (User Controllable JavaScript Event (XSS) - Passive/beta)
|
||||
10044 WARN (Big Redirect Detected (Potential Sensitive Information Leak) - Passive/beta)
|
||||
10045 WARN (Source Code Disclosure - /WEB-INF folder - Active/release)
|
||||
10047 WARN (HTTPS Content Available via HTTP - Active/beta)
|
||||
10048 FAIL (Remote Code Execution - Shell Shock - Active/beta)
|
||||
10050 WARN (Retrieved from Cache - Passive/beta)
|
||||
10051 WARN (Relative Path Confusion - Active/beta)
|
||||
10052 WARN (X-ChromeLogger-Data (XCOLD) Header Information Leak - Passive/beta)
|
||||
10053 WARN (Apache Range Header DoS (CVE-2011-3192) - Active/beta)
|
||||
10054 WARN (Cookie without SameSite Attribute - Passive/release)
|
||||
10055 WARN (CSP - Passive/release)
|
||||
10056 WARN (X-Debug-Token Information Leak - Passive/release)
|
||||
10057 WARN (Username Hash Found - Passive/release)
|
||||
10058 FAIL (GET for POST - Active/beta)
|
||||
10061 WARN (X-AspNet-Version Response Header - Passive/release)
|
||||
10062 FAIL (PII Disclosure - Passive/beta)
|
||||
10095 IGNORE (Backup File Disclosure - Active/beta)
|
||||
10096 WARN (Timestamp Disclosure - Passive/release)
|
||||
10097 WARN (Hash Disclosure - Passive/beta)
|
||||
10098 WARN (Cross-Domain Misconfiguration - Passive/release)
|
||||
10104 WARN (User Agent Fuzzer - Active/beta)
|
||||
10105 WARN (Weak Authentication Method - Passive/release)
|
||||
10106 IGNORE (HTTP Only Site - Active/beta)
|
||||
10107 WARN (Httpoxy - Proxy Header Misuse - Active/beta)
|
||||
10108 WARN (Reverse Tabnabbing - Passive/beta)
|
||||
10109 WARN (Modern Web Application - Passive/beta)
|
||||
10202 WARN (Absence of Anti-CSRF Tokens - Passive/release)
|
||||
2 WARN (Private IP Disclosure - Passive/release)
|
||||
20012 WARN (Anti-CSRF Tokens Check - Active/beta)
|
||||
20014 WARN (HTTP Parameter Pollution - Active/beta)
|
||||
20015 WARN (Heartbleed OpenSSL Vulnerability - Active/beta)
|
||||
20016 WARN (Cross-Domain Misconfiguration - Active/beta)
|
||||
20017 FAIL (Source Code Disclosure - CVE-2012-1823 - Active/beta)
|
||||
20018 FAIL (Remote Code Execution - CVE-2012-1823 - Active/beta)
|
||||
20019 WARN (External Redirect - Active/release)
|
||||
3 WARN (Session ID in URL Rewrite - Passive/release)
|
||||
30001 WARN (Buffer Overflow - Active/release)
|
||||
30002 WARN (Format String Error - Active/release)
|
||||
30003 WARN (Integer Overflow Error - Active/beta)
|
||||
40003 WARN (CRLF Injection - Active/release)
|
||||
40008 WARN (Parameter Tampering - Active/release)
|
||||
40009 WARN (Server Side Include - Active/release)
|
||||
40012 FAIL (Cross Site Scripting (Reflected) - Active/release)
|
||||
40013 FAIL (Session Fixation - Active/beta)
|
||||
40014 FAIL (Cross Site Scripting (Persistent) - Active/release)
|
||||
40016 FAIL (Cross Site Scripting (Persistent) - Prime - Active/release)
|
||||
40017 FAIL (Cross Site Scripting (Persistent) - Spider - Active/release)
|
||||
40018 WARN (SQL Injection - Active/release)
|
||||
40019 FAIL (SQL Injection - MySQL - Active/beta)
|
||||
40020 FAIL (SQL Injection - Hypersonic SQL - Active/beta)
|
||||
40021 FAIL (SQL Injection - Oracle - Active/beta)
|
||||
40022 FAIL (SQL Injection - PostgreSQL - Active/beta)
|
||||
40023 FAIL (Possible Username Enumeration - Active/beta)
|
||||
40024 FAIL (SQL Injection - SQLite - Active/beta)
|
||||
40025 FAIL (Proxy Disclosure - Active/beta)
|
||||
40026 FAIL (Cross Site Scripting (DOM Based) - Active/beta)
|
||||
40027 FAIL (SQL Injection - MsSQL - Active/beta)
|
||||
40028 WARN (ELMAH Information Leak - Active/release)
|
||||
40029 WARN (Trace.axd Information Leak - Active/beta)
|
||||
40032 FAIL (.htaccess Information Leak - Active/release)
|
||||
40034 FAIL (.env Information Leak - Active/beta)
|
||||
40035 FAIL (Hidden File Finder - Active/beta)
|
||||
41 FAIL (Source Code Disclosure - Git - Active/beta)
|
||||
42 WARN (Source Code Disclosure - SVN - Active/beta)
|
||||
43 WARN (Source Code Disclosure - File Inclusion - Active/beta)
|
||||
50000 WARN (Script Active Scan Rules - Active/release)
|
||||
50001 WARN (Script Passive Scan Rules - Passive/release)
|
||||
6 WARN (Path Traversal - Active/release)
|
||||
7 WARN (Remote File Inclusion - Active/release)
|
||||
90001 WARN (Insecure JSF ViewState - Passive/release)
|
||||
90011 WARN (Charset Mismatch - Passive/release)
|
||||
90017 WARN (XSLT Injection - Active/beta)
|
||||
90019 WARN (Server Side Code Injection - Active/release)
|
||||
90020 FAIL (Remote OS Command Injection - Active/release)
|
||||
90021 WARN (XPath Injection - Active/beta)
|
||||
90022 WARN (Application Error Disclosure - Passive/release)
|
||||
90023 WARN (XML External Entity Attack - Active/beta)
|
||||
90024 WARN (Generic Padding Oracle - Active/beta)
|
||||
90025 WARN (Expression Language Injection - Active/beta)
|
||||
90026 WARN (SOAP Action Spoofing - Active/alpha)
|
||||
90027 IGNORE (Cookie Slack Detector - Active/beta)
|
||||
90028 WARN (Insecure HTTP Method - Active/beta)
|
||||
90029 WARN (SOAP XML Injection - Active/alpha)
|
||||
90030 WARN (WSDL File Detection - Passive/alpha)
|
||||
90033 WARN (Loosely Scoped Cookie - Passive/release)
|
||||
90034 WARN (Cloud Metadata Potentially Exposed - Active/beta)
|
||||
Reference in New Issue
Block a user