CI/CD-Integration

Fügen Sie Ihrer Deployment-Pipeline Barrierefreiheitsprüfungen hinzu. AllyProof kann Pull Requests, die WCAG-Verstöße einführen, blockieren oder davor warnen und so Regressionen abfangen, bevor sie in die Produktion gelangen.

Einen API-Schlüssel erstellen

Gehen Sie zu Einstellungen > API-Schlüssel und klicken Sie auf Schlüssel erstellen. Geben Sie ihm einen aussagekräftigen Namen (z. B. github-actions-ci) und kopieren Sie den Schlüssel sofort – er wird nur einmal angezeigt.

Speichern Sie den Schlüssel als Secret in Ihrer CI-Umgebung:

  • GitHub Actions: Settings > Secrets > ALLYPROOF_API_KEY
  • GitLab CI: Settings > CI/CD > Variables > ALLYPROOF_API_KEY

Der Scan-Endpunkt

Lösen Sie einen Scan aus, indem Sie eine POST-Anfrage an die Scan-API senden. Die Website muss bereits in Ihrem AllyProof-Dashboard hinzugefügt und verifiziert sein.

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
}

Anfrageparameter

FeldTypErforderlichBeschreibung
urlstring (URL)JaDie verifizierte Website-URL, die gescannt werden soll.
thresholdnumber (0–100)NeinMindest-Score zum Bestehen. Standard: 0 (besteht immer).
waitbooleanNeinBei true hält die Verbindung offen, bis der Scan abgeschlossen ist (bis zu 270 s, danach wird eine poll_url zurückgegeben). Nur für kleine Websites geeignet – bevorzugen Sie asynchron + Polling. Standard: false.
max_pagesnumber (1–100)NeinMaximale Anzahl zu scannender Seiten. Wenn weggelassen, werden alle gefundenen Seiten bis zum konfigurierten Limit der Website gescannt.

Hinweis: Der API-Schlüssel wird über den x-api-key-Header übergeben, nicht über den Authorization-Header.

Antwortformate

Synchron (wait: true)

Wenn wait auf true steht, hält die API die Verbindung offen, bis der Scan abgeschlossen ist, und gibt Ergebnisse direkt zurück. Nur für kleine Websites empfohlen: Eine lange offene HTTP-Verbindung kann von Proxys und Unternehmens-Gateways getrennt werden, bevor der Scan fertig ist. Nutzen Sie für CI-Pipelines das asynchrone Muster unten – auslösen, dann mit kurzen Anfragen abfragen.

{
  "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"
}

Asynchron (Standard)

Ohne wait: true antwortet die API sofort mit einer Scan-ID und einer Poll-URL. Die Antwort hat den HTTP-Status 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."
}

Um Ergebnisse abzufragen, rufen Sie die in der Antwort mitgelieferte URL mit demselben API-Schlüssel auf:

GET https://allyproof.com/api/v1/scan?id=scan-uuid
x-api-key: <API_KEY>

Konfiguration des Schwellenwerts

Der Parameter threshold legt den minimal akzeptablen Barrierefreiheits-Score fest. Nach Abschluss des Scans:

  • Liegt der Score auf oder über dem Schwellenwert, enthält die Antwort "pass": true
  • Liegt der Score unter dem Schwellenwert, enthält die Antwort "pass": false

Nutzen Sie dies in Ihrem CI-Skript, um zu entscheiden, ob der Pipeline-Schritt besteht oder fehlschlägt. Ein Schwellenwert von 85 ist für die meisten Websites ein vernünftiger Ausgangspunkt. Erhöhen Sie ihn schrittweise, während Sie bestehende Verstöße beheben.

Beispiel für GitHub Actions

Speichern Sie dies als .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
        run: |
          RESPONSE=$(curl -s -X POST \
            https://allyproof.com/api/v1/scan \
            -H "x-api-key: ${{ secrets.ALLYPROOF_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{
              "url": "${{ vars.SITE_URL }}",
              "wait": true,
              "threshold": 85
            }')

          SCORE=$(echo "$RESPONSE" | jq -r '.score')
          PASS=$(echo "$RESPONSE" | jq -r '.pass')
          VIOLATIONS=$(echo "$RESPONSE" | jq -r '.summary.total_violations')
          URL=$(echo "$RESPONSE" | jq -r '.dashboard_url')

          echo "score=$SCORE" >> "$GITHUB_OUTPUT"
          echo "pass=$PASS" >> "$GITHUB_OUTPUT"
          echo "violations=$VIOLATIONS" >> "$GITHUB_OUTPUT"
          echo "url=$URL" >> "$GITHUB_OUTPUT"

      - name: Comment on PR
        if: always()
        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 if below threshold
        if: steps.scan.outputs.pass == 'false'
        run: |
          echo "Accessibility score ${{ steps.scan.outputs.score }} is below threshold"
          exit 1

Beispiel für GitLab CI

Speichern Sie dies als .gitlab-ci.yml:

accessibility:
  stage: test
  image: alpine:latest
  before_script:
    - apk add --no-cache curl jq
  script:
    - |
      RESPONSE=$(curl -s -X POST \
        https://allyproof.com/api/v1/scan \
        -H "x-api-key: $ALLYPROOF_API_KEY" \
        -H "Content-Type: application/json" \
        -d "{
          \"url\": \"$SITE_URL\",
          \"wait\": true,
          \"threshold\": 85
        }")

      SCORE=$(echo "$RESPONSE" | jq -r '.score')
      PASS=$(echo "$RESPONSE" | jq -r '.pass')

      echo "Accessibility Score: $SCORE/100"

      if [ "$PASS" = "false" ]; then
        echo "Score below threshold – failing pipeline"
        exit 1
      fi
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

Bewährte Praktiken

  • Führen Sie Scans bei Pull Requests aus, nicht nur beim Merge nach main – erkennen Sie Regressionen frühzeitig.
  • Beginnen Sie mit einem niedrigen Schwellenwert (z. B. 70) und erhöhen Sie ihn schrittweise, während Sie bestehende Verstöße beheben.
  • Nutzen Sie max_pages, um den Scan-Umfang für schnellere CI-Läufe zu begrenzen.
  • Richten Sie E-Mail-Benachrichtigungen als Backup ein, damit Stakeholder Ergebnisse sehen, auch wenn sie CI nicht prüfen.
  • Nutzen Sie die dashboard_url in PR-Kommentaren, damit Entwickler direkt zum vollständigen Bericht springen können.

Einschränkungen

  • Automatisiertes Scannen deckt etwa 57–70 % der WCAG-2.2-AA-Kriterien ab. Kriterien, die menschliches Urteilsvermögen erfordern (z. B. aussagekräftiger Alt-Text, logische Lesereihenfolge), werden nicht getestet.
  • Scans mit wait: true liefern nach 270 Sekunden eine poll_url, falls der Scan noch läuft. Nutzen Sie für alles außer kleinen Websites den asynchronen Modus mit Polling.
  • Die Website muss in Ihrem AllyProof-Dashboard verifiziert sein, bevor die API sie scannen kann.