Informe SARIF

--sarif <path> escribe un registro SARIF 2.1.0 (el formato estándar que espera GitHub Code Scanning y otros paneles que consumen SARIF), en lugar del resultado sin procesar del motor de --json, o además de él.

$ surea11y scan ./dist/index.html --sarif results.sarif

Ver integración con CI para un flujo de trabajo de GitHub Actions listo para usar que ejecuta un análisis y sube results.sarif a la pestaña "Security".

Por qué un formato separado de --json

El resultado sin procesar de --json (ver Esquema de salida) es el contrato propio de este motor, versionado y estable según API_STABILITY.md. SARIF es un contrato distinto, definido externamente, diseñado específicamente para paneles de análisis de código: una entrada de checksResults[] y un result de SARIF no se corresponden 1:1, así que esto es una conversión real, no una re-serialización.

Qué se convierte en un resultado SARIF

Solo las ocurrencias fail/cantTell producen resultados SARIF (el mismo enfoque de "solo violaciones" que el informe HTML).

Una comprobación notApplicable no siempre está vacía: una regla puede adjuntar una ocurrencia que explica por qué no tuvo nada que juzgar, algo que hacen las reglas de contraste cuando ningún texto tenía un fondo con el que calcular el contraste. Esas nunca se convierten en resultados: un consumidor trata cada resultado como una alerta, y "esto no se evaluó" no lo es. Pero tampoco se descartan. Se incluyen como entradas de nivel note en runs[0].invocations[0].toolExecutionNotices, cada una identificando la regla de la que proviene mediante associatedRule.id:

"invocations": [
{
"executionSuccessful": true,
"toolExecutionNotices": [
{
"level": "note",
"message": { "text": "No eligible text had computable contrast (eligible text nodes: 13). See the contrast computability rule for details." },
"associatedRule": { "id": "contrast-minimum" }
}
]
}
]

Esto evita que un flujo que solo lee SARIF interprete el silencio como un buen estado de salud: que no haya alertas de contraste puede significar que la página está bien o que el contraste nunca fue calculable, y solo la notificación distingue entre ambos casos. El bloque se emite solo cuando hay algo que decir, así que una ejecución sin nada que indicar no tiene ninguna clave invocations.

Resultado del motorNivel SARIFSignificado
failerrorViolación determinista: el caso de bloqueo en CI.
cantTellwarningRequiere revisión humana: se muestra, pero no debería bloquear una compilación por sí sola.

Cada regla que se ejecutó (sin importar si produjo un resultado) se lista una vez en runs[0].tool.driver.rules, con defaultConfiguration.level establecido según el type de la regla: automatic (capaz de fallar) → error, manual (limitada a cantTell como máximo) → warning.

Correspondencia de campos

Campo SARIFOrigen
results[].ruleIdchecksResults[i].ruleId
results[].message.textoccurrence.summary + occurrence.hint
results[].locations[].physicalLocation.artifactLocation.uriEl objetivo analizado (ver Ubicaciones más abajo).
results[].locations[].logicalLocations[].fullyQualifiedNameoccurrence.selector, cuando está presente.
results[].partialFingerprints["surea11y/violation/v1"]La misma clave de identidad ruleId + reasonCode + html que usa Baseline / allowlist (computeBaselineKey): una huella basada en el contenido y estable, no basada en la posición.
results[].properties.severity / .confidence / .reasonCode / .htmlEl propio severity/confidence del resultado, más el mismo reasonCode y fragmento html sobre el que se calcula la huella anterior: informativo, no forma parte del propio esquema de SARIF.
tool.driver.rules[].properties.tagsaccessibility, automatic/manual, y una etiqueta wcag-<SC> por cada meta.normativeMappings[].requirement.

Ubicaciones

El análisis basado en el DOM no tiene línea/columna que indicar, así que physicalLocation.artifactLocation.uri es el propio objetivo analizado, no una posición en un archivo fuente:

  • Análisis de archivos locales: una ruta relativa al directorio de trabajo actual (con barras diagonales). Si esto coincide con un archivo real de tu repositorio, GitHub Code Scanning puede mostrar el hallazgo como una anotación en línea.
  • Análisis de URL: la propia URL analizada. GitHub Code Scanning seguirá listando el hallazgo, pero no puede adjuntar una anotación en línea a una URL que no es un archivo del repositorio: esto es inherente a cómo SARIF/Code Scanning asocian los hallazgos con el código fuente, no una limitación de surea11y. Si necesitas anotaciones en línea, analiza el archivo HTML renderizado (por ejemplo, un artefacto de compilación) en lugar de una URL en vivo.

occurrence.selector se incluye además como un logicalLocations[].fullyQualifiedName, así que un consumidor que lea las ubicaciones lógicas igual obtiene la señal de "qué elemento" incluso sin una ubicación física utilizable.

Combinación con --baseline

Un consumidor genérico de SARIF no tiene un concepto propio de "conocido, no bloquear por esto": la única forma fiel de respetar un baseline en la salida SARIF es omitir por completo las ocurrencias fail ya conocidas, en lugar de rebajarlas a warning:

$ surea11y scan ./dist/index.html --baseline baseline.json --sarif results.sarif

Las ocurrencias cantTell nunca se filtran mediante un baseline: el mecanismo de baseline solo rastrea ocurrencias fail (igual que --write-baseline, ver Baseline / allowlist).

Combinación con --html/--json

--sarif, --html y --json son indicadores de salida independientes: pasa cualquier combinación en una sola ejecución; cada uno escribe o imprime su propio informe a partir del mismo análisis único.