Skip to content

Commit 51fe35b

Browse files
committed
Add first sketch of accessibility scanner.
1 parent 2a9e745 commit 51fe35b

File tree

5 files changed

+171
-1
lines changed

5 files changed

+171
-1
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches: [ main, dev ]
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
11+
services:
12+
postgres:
13+
image: postgres:14
14+
env:
15+
POSTGRES_PASSWORD: postgres
16+
ports:
17+
- 5432:5432
18+
options: >-
19+
--health-cmd pg_isready
20+
--health-interval 10s
21+
--health-timeout 5s
22+
--health-retries 5
23+
24+
steps:
25+
- uses: actions/checkout@v4
26+
27+
- name: Set up Ruby
28+
uses: ruby/setup-ruby@v1
29+
with:
30+
bundler-cache: true
31+
32+
- name: Compile CSS and JS
33+
run: |
34+
35+
yarn install
36+
yarn build
37+
yarn build:css
38+
39+
- name: Set up database
40+
env:
41+
RAILS_ENV: test
42+
DATABASE_URL: postgres://postgres:postgres@localhost:5432/access_pdf_test
43+
run: |
44+
bundle exec rails db:create
45+
bundle exec rails db:migrate
46+
bundle exec rails db:setup
47+
48+
- name: Set up Python
49+
uses: actions/setup-python@v4
50+
with:
51+
python-version: '3.12'
52+
53+
- name: Install Firefox and GeckoDriver
54+
run: |
55+
sudo apt-get update
56+
sudo apt-get install -y firefox-esr wget
57+
sudo rm -rf /var/lib/apt/lists/*
58+
wget -O /tmp/geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/v0.33.0/geckodriver-v0.33.0-linux64.tar.gz
59+
sudo tar -xzf /tmp/geckodriver.tar.gz -C /usr/local/bin/
60+
sudo chmod +x /usr/local/bin/geckodriver
61+
rm /tmp/geckodriver.tar.gz
62+
63+
- name: Install Python dependencies
64+
run: |
65+
python -m pip install --upgrade pip
66+
pip install -r python_components/accessibility_scan/requirements.txt
67+
68+
- name: Run tests
69+
env:
70+
RAILS_ENV: test
71+
DATABASE_URL: postgres://postgres:postgres@localhost:5432/access_pdf_test
72+
run: python python_components/accessibility_scan/main.py

app/views/sessions/new.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"aria-required": true %>
4747
</div>
4848
<div class="form-control mt-6">
49-
<%= form.button type: "submit", class: "btn btn-primary" do %>
49+
<%= form.button type: "submit", id: "submit-session-form", class: "btn btn-primary" do %>
5050
<i class="fas fa-sign-in-alt mr-2"></i>
5151
Login
5252
<% end %>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
FROM python:3.12
2+
ENV PYTHONPATH=\/workspace
3+
WORKDIR /workspace
4+
RUN apt-get update && apt-get install -y \
5+
firefox-esr \
6+
wget \
7+
&& rm -rf /var/lib/apt/lists/*
8+
9+
RUN wget -O /tmp/geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/v0.33.0/geckodriver-v0.33.0-linux64.tar.gz \
10+
&& tar -xzf /tmp/geckodriver.tar.gz -C /usr/local/bin/ \
11+
&& chmod +x /usr/local/bin/geckodriver
12+
13+
COPY requirements.txt .
14+
RUN pip install -r requirements.txt --trusted-host pypi.python.org --no-cache-dir
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import json
2+
3+
from axe_selenium_python import Axe
4+
from selenium import webdriver
5+
from selenium.webdriver.common.by import By
6+
from selenium.webdriver.firefox.options import Options
7+
from selenium.webdriver.firefox.service import Service
8+
from selenium.webdriver.support import expected_conditions as EC
9+
from selenium.webdriver.support.ui import WebDriverWait
10+
11+
TAGS = ["wcag2a", "wcag2aa", "wcag21aa"]
12+
13+
ANON_URLS_TO_SCAN = ("http://host.docker.internal:3000",)
14+
15+
AUTHED_URLS_TO_SCAN = (
16+
"http://host.docker.internal:3000/sites",
17+
"http://host.docker.internal:3000/sites/1/documents"
18+
"http://host.docker.internal:3000/sites/1/insights",
19+
)
20+
21+
22+
def scan_urls():
23+
# Automatically manage geckodriver
24+
options = Options()
25+
options.add_argument("--headless")
26+
options.add_argument("--no-sandbox")
27+
options.add_argument("--disable-dev-shm-usage")
28+
29+
service = Service("/usr/local/bin/geckodriver")
30+
driver = webdriver.Firefox(service=service, options=options)
31+
32+
all_results = {
33+
"total_violations": 0,
34+
"anon_urls": {},
35+
"authed_urls": {},
36+
}
37+
38+
for url in ANON_URLS_TO_SCAN:
39+
driver.get(url)
40+
driver.implicitly_wait(5)
41+
results = get_axe_results(driver)
42+
all_results["total_violations"] += len(results["violations"])
43+
all_results["anon_urls"][url] = results
44+
45+
# Log into the app.
46+
wait = WebDriverWait(driver, 10)
47+
email_field = wait.until(
48+
EC.presence_of_element_located((By.CSS_SELECTOR, "#email_address"))
49+
)
50+
password_field = driver.find_element(By.CSS_SELECTOR, "#password")
51+
email_field.send_keys("[email protected]")
52+
password_field.send_keys("password")
53+
submit_button = driver.find_element(By.CSS_SELECTOR, "#submit-session-form")
54+
submit_button.click()
55+
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#add-site-modal")))
56+
57+
for url in AUTHED_URLS_TO_SCAN:
58+
driver.get(url)
59+
driver.implicitly_wait(5)
60+
results = get_axe_results(driver)
61+
all_results["total_violations"] += len(results["violations"])
62+
all_results["authed_urls"][url] = results
63+
64+
driver.quit()
65+
66+
print(json.dumps(all_results, indent=2))
67+
68+
69+
def get_axe_results(driver):
70+
axe = Axe(driver)
71+
axe.inject()
72+
return axe.run({"runOnly": {"type": "tag", "values": TAGS}})
73+
74+
75+
if __name__ == "__main__":
76+
scan_urls()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
axe-selenium-python==2.1.6
2+
backports.tarfile==1.2.0
3+
importlib-metadata==8.0.0
4+
jaraco.collections==5.1.0
5+
pip-chill==1.0.3
6+
platformdirs==4.2.2
7+
pysocks==1.7.1
8+
tomli==2.0.1

0 commit comments

Comments
 (0)