Skip to main content

verifactu-lint

ci OpenSSF Scorecard PyPI Python License

Audita registros de facturación ya emitidos contra el Reglamento de requisitos de los sistemas informáticos de facturación (RD 1007/2023) y su Orden de desarrollo (HAC/1177/2024).

Le das el XML que tu sistema genera y te dice dónde incumple, citando el artículo.

$ verifactu-lint registros-2026-01.xml

verifactu-lint · 1.284 registros · registros-2026-01.xml

ERROR      RRSIF003 [#412 FA/2026/0412]: La cadena se rompe en este registro
           Declara como huella anterior 9F2C…A31B, y la huella de #411 FA/2026/0411 es 4D77…C0E9.
           Una cadena rota significa que la secuencia conservada no es la que se generó:
           falta un registro por medio, se reordenaron, o se modificó uno después de emitirlo.
           norma: Orden HAC/1177/2024, art. 13 y especificaciones técnicas de la huella

1 errores · 0 avisos · 0 sin determinar

Qué es, y qué no es

Existen ya varias librerías buenas para generar registros Verifactu. Ninguna responde a la pregunta que se hace quien ya tiene un sistema en marcha: ¿lo que llevo emitido cumple?

Eso es lo que hace esta herramienta.

No es un sistema informático de facturación. No expide facturas, no genera registros, no los firma y no los remite a la AEAT. Sólo lee. Por tanto no le corresponde emitir declaración responsable alguna, ni la emite.

Un resultado sin errores no acredita conformidad. Significa que estas reglas, sobre esos registros, no han encontrado un incumplimiento. La declaración responsable del artículo 13 del RRSIF la emite el productor del SIF bajo su propia responsabilidad, y ninguna herramienta puede emitirla por él.

Instalación

pip install verifactu-lint

Sin dependencias en tiempo de ejecución: sólo la biblioteca estándar de Python (3.11+).

Uso

# informe legible
verifactu-lint registros.xml

# varios ficheros; cada uno se audita como su propia cadena
verifactu-lint enero.xml febrero.xml

# para tratarlo con jq, o para archivarlo
verifactu-lint registros.xml --formato json

# para GitHub Code Scanning
verifactu-lint registros.xml --formato sarif > verifactu.sarif

# que los avisos también rompan la build
verifactu-lint registros.xml --estricto

Códigos de salida: 0 sin errores · 1 con errores (o con avisos si --estricto) · 2 si el fichero no se pudo leer.

Como librería:

from verifactu_lint.registros import lee
from verifactu_lint.reglas import audita

informe = audita(lee("registros.xml"))
for hallazgo in informe.errores:
    print(hallazgo.regla, hallazgo.titulo, hallazgo.referencia)

En tu CI

Auditar en cada cambio cuesta menos que descubrir la cadena rota en una inspección. Con salida SARIF los hallazgos aparecen en la pestaña Security del repositorio, sin que nadie tenga que abrir un log:

name: verifactu
on: [push, pull_request]

permissions:
  contents: read

jobs:
  auditar:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: easybytehub/verifactu-lint@v0.2.0
        with:
          ficheros: "registros/*.xml"
          fallar: "false"      # que no aborte antes de subir el informe
      - uses: github/codeql-action/upload-sarif@v3
        with: { sarif_file: verifactu-lint.sarif }

fallar: false es deliberado: sin él, un hallazgo abortaría el job antes de subir el SARIF y verías que falla sin poder ver por qué. El fallo lo señala la pestaña Security, que es donde se puede leer.

Entrada Por defecto
ficheros Ficheros a auditar. Admite comodines.
formato sarif texto, json o sarif.
estricto false Que los avisos también hagan fallar.
fallar true Si false, el paso no falla aunque haya hallazgos.
salida verifactu-lint.sarif Fichero del informe.
version la de la action Versión de verifactu-lint a instalar.

Salidas: errores, avisos (con formato: json) y fichero-informe.

La action fija la versión que instala en vez de coger la última: una action que instala «lo último» cambia de comportamiento sin que nadie haya tocado nada.

Si prefieres no usar la action, la CLI hace lo mismo:

pip install verifactu-lint
verifactu-lint registros/*.xml --formato sarif > verifactu.sarif

Las reglas

Registros de facturación (alta y anulación):

Regla Comprueba
RRSIF001 La huella declarada sale de los campos del registro
RRSIF002 La huella tiene 64 caracteres hexadecimales en mayúsculas
RRSIF003 Cada registro encadena con la huella del anterior
RRSIF004 PrimerRegistro y RegistroAnterior son coherentes y hay un único inicio de cadena
RRSIF005 TipoHuella es 01 (SHA-256), el único que admite la lista L12
RRSIF010 No hay numeración de factura duplicada
RRSIF011 El SIF se identifica con NIF + IdSistemaInformatico + NumeroInstalacion
RRSIF012 IndicadorMultiplesOT es coherente con TipoUsoPosibleMultiOT
RRSIF013 La cadena pertenece a un único obligado tributario
RRSIF030 TipoFactura está entre los ocho de la lista L2
RRSIF031 Una rectificativa declara su modalidad y qué factura rectifica
RRSIF032 Los campos de rectificación no aparecen en facturas normales
RRSIF033 Una sustitutiva (S) declara los importes que rectifica
RRSIF034 Una F3 identifica las simplificadas a las que sustituye
RRSIF035 Subsanacion y RechazoPrevio son válidos y no se confunden con rectificar

Registros de evento — es decir, la modalidad NO VERI*FACTU:

Regla Comprueba
RRSIF020 TipoEvento está entre los once del esquema oficial
RRSIF021 La huella del evento sale de sus nueve campos
RRSIF022 Formato de HuellaEvento
RRSIF023 Cada evento encadena con la huella del evento anterior
RRSIF024 PrimerEvento y EventoAnterior son excluyentes, y hay un único origen
RRSIF025 Todo registro de evento lleva firma electrónica
RRSIF026 DatosPropiosEvento corresponde al tipo de evento
RRSIF027 Los arranques y paradas como NO VERI*FACTU se emparejan
RRSIF028 Existe registro resumen de eventos

Si tu sistema opera en NO VERI*FACTU, esta segunda tabla es la que te concierne. La AEAT es explícita en que esa modalidad es técnicamente más exigente que VERI*FACTU: al no remitir los registros a la sede, la integridad y la trazabilidad hay que demostrarlas con el registro de eventos, su encadenamiento propio y su firma. Mucha implementación la elige creyendo que es la opción de menos trabajo.

Tres severidades, no dos

  • error — incumple. Lo que hay en el fichero contradice la norma citada.
  • aviso — muy probablemente incumple, o incumplirá en cuanto se dé una condición previsible.
  • incompleto — no se puede determinar con este fichero, y el hallazgo dice qué habría que mirar.

incompleto existe porque en una herramienta de cumplimiento afirmar un incumplimiento que no existe es peor que callar uno que sí: quien lo lee cambia código correcto y deja de creerse el resto del informe. Cuando una regla no puede concluir, lo dice.

Un ejemplo real de esa cautela: la orden admite 123.1 y 123.10 como el mismo importe, y cada forma produce un SHA-256 distinto. Un verificador que calculase sólo una declararía incorrecta una huella que la AEAT acepta. verifactu-lint prueba las formas admisibles antes de afirmar nada.

Sobre qué se apoya

  • RD 1007/2023, de 5 de diciembre — Reglamento de requisitos de los sistemas informáticos de facturación.
  • Orden HAC/1177/2024, de 17 de octubre — especificaciones técnicas, funcionales y de contenido.
  • AEAT — Detalle de las especificaciones técnicas para generación de la huella o hash de los registros de facturación, v0.1.2 (27/08/2024). Los tres vectores de su apartado 6 están en la suite de tests y se ejecutan en cada cambio: son la definición de correcto para el cálculo de la huella.
  • AEAT — Aclaraciones a dudas de los desarrolladores, v1.3 (04/12/2025).

Cuando una regla y la norma discrepen, la norma tiene razón y la regla es un bug. Abre un issue citando el apartado.

Alcance actual

Cubre el encadenamiento, el formato de la huella y la identificación del SIF sobre registros de alta y anulación, y el encadenamiento, la firma y la coherencia de los registros de evento.

Cada fichero se audita detectando qué contiene. Las dos cadenas —facturación y eventos— se auditan por separado porque son independientes: un evento no encadena con una factura ni al revés.

Todavía no cubre: la tipificación de rectificativas y subsanaciones, ni los requisitos de conservación de la modalidad NO VERI*FACTU que no se pueden observar desde un fichero de registros. Están en los issues.

Contribuir

Una regla es una función list[Registro] -> list[Hallazgo]. No hay clase base, ni registro por decorador, ni sistema de plugins: escribes la función, la añades a la tupla REGLAS de su familia en src/verifactu_lint/reglas/, y le pones un test.

Toda regla nueva necesita: la cita normativa concreta, una severidad justificada, y un test con un caso que la dispare y otro que no. Las reglas que producirían ruido en ficheros grandes deben agregar — un hallazgo por campo, no uno por registro.

git clone https://github.com/easybytehub/verifactu-lint
cd verifactu-lint
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest
.venv/bin/python -m ruff check .
.venv/bin/python -m mypy

Procedencia

Cada release publica su procedencia mediante attestations de GitHub, firmadas con OIDC efímero. No hay ninguna clave privada custodiada por nadie.

gh attestation verify --owner easybytehub verifactu_lint-*.whl

La atestación dice qué commit, qué workflow y qué runner produjeron ese artefacto exacto. Si vas a meter código de terceros en el sistema del que respondes tú, esto es lo que deberías poder comprobar de cualquiera de ellos.

Licencia

Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

verifactu_lint-0.2.0.tar.gz (54.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

verifactu_lint-0.2.0-py3-none-any.whl (38.9 kB view details)

Uploaded Python 3

File details

Details for the file verifactu_lint-0.2.0.tar.gz.

File metadata

  • Download URL: verifactu_lint-0.2.0.tar.gz
  • Upload date:
  • Size: 54.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for verifactu_lint-0.2.0.tar.gz
Algorithm Hash digest
SHA256 7b76aeb6c3af689795a2f5a1f8b1a5c10d566bc63b24a0f6db009851785aa2d0
MD5 aa30b1a565274c1cc0186a0ce580ef15
BLAKE2b-256 06ff2be73c078ced68c92ae9960628cafb6c4fa74929a328f2713431082d27c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for verifactu_lint-0.2.0.tar.gz:

Publisher: release.yml on easybytehub/verifactu-lint

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file verifactu_lint-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: verifactu_lint-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 38.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for verifactu_lint-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 690d826812435618a87ba312308df014dd3a5dd0a3b3c85f229d87377da20dfd
MD5 e32062029dcdba3d02c12cf2ee892b4d
BLAKE2b-256 f1ee4ac55e5691ffeaf449326049e4414d8de00cd2eced0e84559587d9616337

See more details on using hashes here.

Provenance

The following attestation bundles were made for verifactu_lint-0.2.0-py3-none-any.whl:

Publisher: release.yml on easybytehub/verifactu-lint

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page