Files
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

86 lines
6.3 KiB
Markdown

# 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.