Files
govoplan-xrechnung/docs/INBOUND_VALIDATION.md
T
zemion b73709c65a fix(xrechnung): bound validator output and report reads
Enforce capture limits while draining both subprocess pipes, kill and reap interrupted validators, and bound report allocation before parsing. Preserve result precedence and add synthetic-process regressions with EN/DE documentation.

Refs #2
2026-09-08 05:32:37 +02:00

6.3 KiB

Inbound XRechnung validation

This module validates an inbound XML invoice through a locally installed, exact KoSIT validator profile. It does not choose the active standard release, download validation artifacts at runtime, approve a payable, or book an invoice.

Pinned profile

An administrator records the XRechnung version, validator version, configuration release, absolute Java and JAR paths, JAR SHA-256, configuration root and complete deterministic tree SHA-256, scenario file, and expected minimum validation-step count. Every run rechecks the executable and both artifact digests. Symbolic links and files outside the configuration root are rejected.

Deployment-owned profile allow-list

KoSITProfileRegistry allows a deployment to approve several exact profiles without GovOPlaN choosing a standard version. Each approval binds the verified artifact digest, approving actor, decision reference, receive-time window, and the state approved, suspended, or retired. A deployment may configure one explicit default, or require the invoking workflow to select a profile every time. A default is never inferred.

Selection uses the invoice receive time, which permits an administrator to model an overlap or transition window. Suspended, retired, unknown, expired, not-yet-valid, or subsequently modified profiles fail closed. Artifact digests are rechecked on selection and again during validation.

Administrierende können damit mehrere konkrete Profile zeitlich begrenzt freigeben, ohne dass GovOPlaN eine XRechnungs-Version vorgibt. Übergangsfristen und ein Standardprofil sind ausdrücklich konfigurierte Entscheidungen. Ohne Standard muss jeder aufrufende Prozess ein freigegebenes Profil benennen.

The configuration tree must be installed through deployment governance. A newer published release never becomes active automatically. Updating any artifact creates a different profile digest and requires regression evidence with accepted, rejected, malformed, and deliberately broken technical fixtures.

Fail-closed validation

Inbound XML is size-bounded and parsed with external entities and DTD processing disabled before Java runs. KoSIT runs without a shell, with an absolute executable, fixed argument vector, bounded time, bounded captured output, and an isolated result directory.

The validator's stdout and stderr share a fixed 2 MiB capture limit, including the single separator byte used when inspecting their combined output. Both streams are drained while the validator runs. If the next byte exceeds that limit, GovOPlaN kills and reaps the direct validator process and returns failed with the reason KoSIT runner output exceeded the safety limit. Conformance and assessment remain unknown, and no handoff is allowed even if a valid-looking report was already written. The existing timeout (120 seconds by default, configurable from 1 to 600 seconds) also kills and reaps the validator; cancellation propagates after the same cleanup. Output is not included in these technical-failure reasons. Operators should check the approved engine and configuration using synthetic inputs before retrying an output-limit failure. The pipe runner uses POSIX process facilities; deployment resource limits and descendant-process isolation remain outside this capture bound.

Report reads are bounded to the existing 16 MiB limit plus one probe byte. Reports exactly at the limit remain eligible for normal interpretation; oversized reports cannot supply trusted evidence and yield incomplete with unknown conformance unless an earlier runner failure already determines the outcome. An output-limit failure skips reading the report entirely. This read bound does not limit how much report data the validator can write to disk.

Standardausgabe und Standardfehlerausgabe des Validators teilen eine feste Erfassungsgrenze von 2 MiB einschließlich eines Trennbytes. Beide Ausgaben werden während des Laufs gelesen. Bei Überschreitung beendet GovOPlaN den direkten Validatorprozess und wartet dessen Abschluss ab. Das Ergebnis lautet failed mit unbekannter Konformität und Bewertung (unknown); auch ein scheinbar gültiger Bericht erlaubt keine Übergabe. Das bestehende Zeitlimit (standardmäßig 120 Sekunden, konfigurierbar von 1 bis 600 Sekunden) beendet den Prozess ebenfalls; ein Abbruch wird nach der Prozessbereinigung weitergegeben. Diese technischen Fehlergründe enthalten keine Runner-Ausgabe. Betreibende sollten das freigegebene Profil vor einem erneuten Versuch mit synthetischen Eingaben prüfen. Der Pipe-Runner verwendet POSIX-Prozessfunktionen; Ressourcengrenzen der Installation und die Isolation von Kindprozessen bleiben außerhalb dieser Erfassungsgrenze.

Berichte werden höchstens bis zur bestehenden Grenze von 16 MiB zuzüglich eines Prüfbytes gelesen. Berichte genau an der Grenze werden normal ausgewertet; übergroße Berichte liefern keinen vertrauenswürdigen Nachweis und ergeben incomplete mit unbekannter Konformität, sofern nicht bereits ein vorrangiger Runner-Fehler das Ergebnis bestimmt. Bei Überschreitung der Runner-Ausgabegrenze wird der Bericht gar nicht gelesen. Die Lesegrenze begrenzt nicht die Berichtsmenge, die der Validator auf Datenträger schreiben kann.

GovOPlaN does not trust the report alone. A technically complete result requires a zero process status, no technical error marker in runner output, a bounded well-formed VARL report, a matched scenario, at least the configured number of complete validation steps, and exactly one assessment. Formal validity and the accept/reject recommendation are retained separately because warnings can make them differ. This compensates for the known risk that a partial report can look valid after a transformation failure.

Semantic invalidity is different from technical failure. A complete reject report is invalid; a timeout, crash, partial report, or inconsistent assessment is unknown. Neither result may be handed off as valid.

Governed handoff

Only a technically complete, formally valid, and explicitly accepted result creates a handoff. The handoff binds tenant, source reference, invoice SHA-256, VARL report SHA-256, profile ID and profile SHA-256, and validation time. Procurement or Payments owns the later payable workflow; Files owns retained invoice bytes; Records may file an exact revision. Revalidation is mandatory after invoice or profile changes.