Intégration CI/CD
Ajoutez des vérifications d'accessibilité à votre chaîne de déploiement. AllyProof peut bloquer ou signaler les demandes de fusion qui introduisent des non-conformités WCAG, et détecter ainsi les régressions avant la mise en production.
Business inclut les clés d'API, la CLI, les outils MCP authentifiés et l'intégration CI/CD. Les propriétaires et administrateurs de l'organisation peuvent créer des clés. Free n'inclut pas les clés d'API ; l'outil MCP public scan_url reste disponible sans clé.
Générer une clé d'API
Rendez-vous dans Réglages > Clés API et cliquez sur Créer une clé. Donnez-lui un nom explicite (par exemple github-actions-ci) et copiez la clé immédiatement : elle n'est affichée qu'une seule fois.
Conservez la clé comme secret dans votre environnement d'intégration continue :
- GitHub Actions :
Settings > Secrets > ALLYPROOF_API_KEY - GitLab CI :
Settings > CI/CD > Variables > ALLYPROOF_API_KEY
Le point d'accès d'analyse
Déclenchez une analyse en envoyant une requête POST à l'API. Le site doit déjà être ajouté et vérifié dans votre tableau de bord AllyProof.
POST https://allyproof.com/api/v1/scan
x-api-key: <API_KEY>
Content-Type: application/json
{
"url": "https://example.com",
"threshold": 85,
"wait": true,
"max_pages": 20,
"source": "github_actions"
}
Paramètres de la requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
url | chaîne (URL) | Oui | L'URL du site vérifié à analyser. |
threshold | nombre (0-100) | Non | Score minimal pour réussir. Valeur par défaut : 0 (réussite systématique). |
wait | booléen | Non | Si true, maintient la connexion jusqu'à la fin de l'analyse (jusqu'à 270 s, puis renvoie une poll_url). Convient seulement aux petits sites : préférez le mode asynchrone avec interrogation. Valeur par défaut : false. |
max_pages | nombre (1-100) | Non | Nombre maximal de pages à analyser. S'il est omis, toutes les pages découvertes sont analysées, dans la limite configurée pour le site. |
source | chaîne | Non | Le système qui a déclenché l'analyse. Affiché dans la colonne Source de l'historique du site. Valeur par défaut : api. |
Nommer la source
L'historique d'un site liste toutes ses analyses, quelle qu'en soit l'origine : le tableau de bord, les exécutions planifiées, l'interface en ligne de commande, les outils MCP et vos chaînes d'intégration. Le champ source est ce qui distingue un contrôle de mise en production d'un clic sur « Scan Now » trois semaines plus tard.
Renseignez-le avec l'une des valeurs github_actions, gitlab_ci, jenkins, circleci, bitbucket, azure_pipelines, other_ci. Les graphies courantes comme github ou gitlab sont acceptées et normalisées ; toute valeur non reconnue retombe sur api au lieu de faire échouer la requête, afin qu'une coquille dans un fichier de flux ne puisse jamais casser une construction.
Pourquoi vous devez l'indiquer. Les exemples ci-dessous exécutent curl dans votre exécuteur, et curl s'identifie comme curl : l'identité de l'exécuteur ne nous parvient jamais. Nous préférons demander plutôt que deviner et étiqueter votre chaîne GitLab comme GitHub. L'interface en ligne de commande fait exception : elle lit GITHUB_ACTIONS, GITLAB_CI, JENKINS_URL et leurs équivalents dans l'environnement et déclare d'elle-même la bonne source ; allyproof scan dans une chaîne ne demande donc aucune configuration.
Remarque : la clé d'API se transmet par l'en-tête x-api-key, et non par l'en-tête Authorization.
Formats de réponse
Synchrone (wait: true)
Lorsque wait vaut true, l'API maintient la connexion ouverte jusqu'à la fin de l'analyse et renvoie directement les résultats. Recommandé uniquement pour les petits sites : une connexion HTTP maintenue longtemps peut être coupée par un mandataire ou une passerelle d'entreprise avant la fin de l'analyse. Pour les chaînes d'intégration, utilisez le mode asynchrone ci-dessous : déclenchez, puis interrogez par de courtes requêtes.
{
"pass": true,
"score": 92,
"threshold": 85,
"scan_id": "scan-uuid",
"site": { "name": "My Site", "url": "https://example.com" },
"summary": {
"pages_scanned": 12,
"pages_failed": 0,
"total_violations": 3,
"critical": 0,
"serious": 1,
"moderate": 2,
"minor": 0
},
"duration_ms": 14200,
"top_violations": [
{
"rule_id": "color-contrast",
"impact": "serious",
"description": "Elements must meet minimum color contrast ratio thresholds",
"pages_affected": 3
}
],
"pages": [
{ "url": "example.com/", "violations": 1, "critical": 0 },
{ "url": "example.com/about", "violations": 2, "critical": 0 }
],
"dashboard_url": "https://allyproof.com/sites/site-uuid"
}
Asynchrone (par défaut)
Sans wait: true, l'API répond immédiatement avec un identifiant d'analyse et une URL d'interrogation. La réponse porte le code HTTP 202 Accepted.
{
"scan_id": "scan-uuid",
"status": "pending",
"poll_url": "/api/v1/scan?id=scan-uuid",
"message": "Scan started. Poll the poll_url for results, or use wait=true to block."
}
Pour obtenir les résultats, interrogez l'URL fournie dans la réponse avec la même clé d'API :
GET https://allyproof.com/api/v1/scan?id=scan-uuid&threshold=85
x-api-key: <API_KEY>
Répétez le threshold dans l'URL d'interrogation. La réponse calcule pass à partir du seuil présent dans sa propre URL ; sans lui, toute analyse terminée réussit.
Configurer le seuil
Le paramètre threshold fixe le score d'accessibilité minimal acceptable. À la fin de l'analyse :
- si le score atteint ou dépasse le seuil, la réponse contient
"pass": true; - s'il est inférieur au seuil, la réponse contient
"pass": false.
Utilisez cette valeur dans votre script pour décider de faire réussir ou échouer l'étape. Un seuil de 85 constitue un point de départ raisonnable pour la plupart des sites. Relevez-le progressivement à mesure que vous corrigez les non-conformités existantes.
Exemple GitHub Actions
À enregistrer sous .github/workflows/accessibility.yml :
name: Accessibility Check
on:
pull_request:
branches: [main]
jobs:
a11y-scan:
runs-on: ubuntu-latest
steps:
- name: Run AllyProof scan
id: scan
env:
ALLYPROOF_API_KEY: ${{ secrets.ALLYPROOF_API_KEY }}
SITE_URL: ${{ vars.SITE_URL }}
run: |
set -euo pipefail
API=https://allyproof.com/api/v1/scan
THRESHOLD=85
START=$(curl -sS -X POST "$API" \
-H "x-api-key: $ALLYPROOF_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"url\": \"$SITE_URL\", \"threshold\": $THRESHOLD, \"source\": \"github_actions\"}")
SCAN_ID=$(echo "$START" | jq -r '.scan_id // empty')
if [ -z "$SCAN_ID" ]; then
echo "Could not start the scan: $START"
exit 1
fi
# Poll for up to 20 minutes. Repeat the threshold: the poll
# response computes pass against the threshold in its own URL.
RESULT=""
for _ in $(seq 1 80); do
RESULT=$(curl -sS "$API?id=$SCAN_ID&threshold=$THRESHOLD" -H "x-api-key: $ALLYPROOF_API_KEY")
case "$(echo "$RESULT" | jq -r '.status // "error"')" in
completed|failed|error) break ;;
esac
sleep 15
done
echo "$RESULT" | jq '{status, score, threshold, pass, summary, dashboard_url, error}'
{
echo "score=$(echo "$RESULT" | jq -r '.score // empty')"
echo "violations=$(echo "$RESULT" | jq -r '.summary.total_violations // empty')"
echo "url=$(echo "$RESULT" | jq -r '.dashboard_url // empty')"
echo "pass=$(echo "$RESULT" | jq -r '.pass == true')"
} >> "$GITHUB_OUTPUT"
- name: Comment on PR
if: always() && steps.scan.outputs.score != ''
uses: actions/github-script@v7
with:
script: |
const score = '${{ steps.scan.outputs.score }}';
const violations = '${{ steps.scan.outputs.violations }}';
const url = '${{ steps.scan.outputs.url }}';
const passed = '${{ steps.scan.outputs.pass }}' === 'true';
const emoji = passed ? '✅' : '❌';
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `${emoji} **AllyProof Scan**\n\nScore: **${score}/100** | Violations: **${violations}**\n\n[View full report](${url})`
});
- name: Fail unless the scan passed
if: steps.scan.outputs.pass != 'true'
run: |
echo "Accessibility gate did not pass (score: ${{ steps.scan.outputs.score }})"
exit 1
Les deux exemples échouent par défaut : le build ne réussit que si l'analyse se termine avec un score égal ou supérieur au seuil. Une clé d'API refusée, une analyse en échec ou une analyse toujours en cours après 20 minutes fait échouer l'étape.
Exemple GitLab CI
À enregistrer sous .gitlab-ci.yml :
accessibility:
stage: test
image: alpine:latest
before_script:
- apk add --no-cache curl jq
script:
- |
set -eu
API=https://allyproof.com/api/v1/scan
THRESHOLD=85
START=$(curl -sS -X POST "$API" \
-H "x-api-key: $ALLYPROOF_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"url\": \"$SITE_URL\", \"threshold\": $THRESHOLD, \"source\": \"gitlab_ci\"}")
SCAN_ID=$(echo "$START" | jq -r '.scan_id // empty')
if [ -z "$SCAN_ID" ]; then echo "Could not start the scan: $START"; exit 1; fi
RESULT=""
for _ in $(seq 1 80); do
RESULT=$(curl -sS "$API?id=$SCAN_ID&threshold=$THRESHOLD" -H "x-api-key: $ALLYPROOF_API_KEY")
case "$(echo "$RESULT" | jq -r '.status // "error"')" in
completed|failed|error) break ;;
esac
sleep 15
done
echo "$RESULT" | jq '{status, score, threshold, pass, error}'
if [ "$(echo "$RESULT" | jq -r '.pass == true')" != "true" ]; then
echo "Accessibility gate did not pass - failing pipeline"
exit 1
fi
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
Bonnes pratiques
- Lancez les analyses sur les demandes de fusion, et pas seulement à la fusion dans la branche principale : vous détecterez les régressions plus tôt.
- Commencez avec un seuil bas (par exemple
70) et relevez-le progressivement à mesure que vous corrigez les non-conformités existantes. - Utilisez
max_pagespour restreindre l'étendue de l'analyse et accélérer les exécutions. - Configurez les notifications par courriel en complément, afin que les parties prenantes voient les résultats même sans consulter la chaîne d'intégration.
- Utilisez
dashboard_urldans les commentaires de demande de fusion, pour que les personnes développeuses accèdent directement au rapport complet. - Renseignez
source, afin que l'historique indique quelle chaîne a lancé chaque analyse : sans cela, toute analyse automatisée apparaît comme un appel d'API générique.
Limites
- L'analyse automatisée détecte des schémas d'échec courants au regard des WCAG 2.2 niveau AA, non l'ensemble des défaillances, et une construction au vert n'est pas un résultat de conformité. Les critères qui exigent un jugement humain - pertinence d'une alternative textuelle, ordre de lecture logique - ne sont pas testés du tout.
- Les analyses lancées avec
wait: truerenvoient unepoll_urlau bout de 270 secondes si l'analyse est toujours en cours. Pour tout site qui n'est pas de petite taille, utilisez le mode asynchrone avec interrogation. - Le site doit être vérifié dans votre tableau de bord AllyProof avant que l'API puisse l'analyser.