Merge pull request #117 from cisagov/nmb/pa11y-scanning

Automated accessibility scanning
This commit is contained in:
Neil MartinsenBurrell 2022-09-14 14:28:59 -05:00 committed by GitHub
commit 98bc594203
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1346 additions and 283 deletions

View file

@ -12,61 +12,30 @@ on:
jobs:
python-linting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
- name: Install linters
run: |
python -m pip install --upgrade pip
pip install bandit black flake8 mypy types-requests
- name: Lint with flake8
- name: Linting
working-directory: ./src
run: flake8 . --count --show-source --statistics
- name: Check formatting with black
working-directory: ./src
run: black --check .
- name: Run type checking
working-directory: ./src
run: mypy .
- name: Run bandit security scanning
working-directory: ./src
run: bandit -r .
# all of our linting is configured in
# registrar/management/commands/lint.py
run: docker compose run app python manage.py lint
python-test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres
env:
POSTGRES_DB: app
POSTGRES_USER: user
POSTGRES_PASSWORD: feedabee
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
- name: Install Django
- name: Unit tests
working-directory: ./src
run: |
python -m pip install --upgrade pip
pip install pipenv
pipenv install --system --dev
- name: Test
run: docker compose run app python manage.py test
pa11y-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Accessibility Scan
working-directory: ./src
env:
PYTHONUNBUFFERED: yup
DATABASE_URL: postgres://user:feedabee@localhost/app
DJANGO_SETTINGS_MODULE: registrar.config.settings
DJANGO_SECRET_KEY: feedabee
DJANGO_DEBUG: True
run: ./manage.py test
# leverage the docker compose setup that we already have for local development
run: docker compose run pa11y npm run pa11y-ci

View file

@ -62,6 +62,20 @@ Linters:
docker-compose exec app ./manage.py lint
```
## Accessibility Scanning
The tool `pa11y-ci` is used to scan pages for compliance with a set of
accessibility rules. The scan runs as part of our CI setup (see
`.github/workflows/test.yaml`) but it can also be run locally. To run locally,
type
```shell
docker-compose run pa11y npm run pa11y-ci
```
The URLs that `pa11y-ci` will scan are configured in `src/.pa11yci`. When new
views and pages are added, their URLs should also be added to that file.
## USWDS and styling
We use the U.S. Web Design System (USWDS) for building and styling our applications. Additionally, we utilize the [uswds-compile tool](https://designsystem.digital.gov/documentation/getting-started/developers/phase-two-compile/) from USWDS to compile and package the static assets.
When you run `docker-compose up` the `node` service in the container will begin to watch for changes in the `registrar/assets` folder, and will recompile once any changes are made.

6
src/.pa11yci Normal file
View file

@ -0,0 +1,6 @@
{
"urls": [
"http://app:8080/",
"http://app:8080/health/"
]
}

View file

@ -49,3 +49,20 @@ services:
stdin_open: true
tty: true
command: ./run_node_watch.sh
pa11y:
build:
context: .
dockerfile: node.Dockerfile
cap_add:
- SYS_ADMIN
volumes:
- .:/app
# internal Docker volume that will cover up the host's
# node_modules directory inside of the container
- /app/node_modules
working_dir: /app
links:
- app
profiles:
- pa11y

10
src/node.Dockerfile Normal file
View file

@ -0,0 +1,10 @@
FROM docker.io/cimg/node:current-browsers
WORKDIR /app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY --chown=circleci:circleci package*.json ./
RUN npm install

1491
src/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -4,12 +4,14 @@
"description": "========================",
"main": "index.js",
"scripts": {
"pa11y-ci": "pa11y-ci",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@uswds/uswds": "^3.1.0",
"pa11y-ci": "^3.0.1",
"sass": "^1.54.8"
},
"devDependencies": {

View file

@ -158,6 +158,7 @@ TEMPLATES = [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"registrar.context_processors.language_code",
],
},
},
@ -493,8 +494,8 @@ if DEBUG:
"::1",
]
# allow dev laptop to connect
ALLOWED_HOSTS += ("localhost",)
# allow dev laptop and docker-compose network to connect
ALLOWED_HOSTS += ("localhost", "app")
SECURE_SSL_REDIRECT = False
SECURE_HSTS_PRELOAD = False

View file

@ -0,0 +1,13 @@
from django.conf import settings
def language_code(request):
"""Add LANGUAGE_CODE to the template context.
The <html> element of a web page should include a lang="..." attribute. In
Django, the correct thing to put in that attribute is the value of
settings.LANGUAGE_CODE but the template context can't access that value
unless we add it here (and configure this context processor in the
TEMPLATES dict of our settings file).
"""
return {"LANGUAGE_CODE": settings.LANGUAGE_CODE}

View file

@ -8,4 +8,4 @@ class HealthTest(TestCase):
def test_health_check_endpoint(self):
response = self.client.get("/health/")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"OK")
self.assertContains(response, "OK")

View file

@ -2,4 +2,6 @@ from django.http import HttpResponse
def health(request):
return HttpResponse("OK")
return HttpResponse(
'<html lang="en"><head><title>OK - Get.gov</title></head><body>OK</body>'
)