cadrumo.adapters.inbound.einvoice.xml module¶
Hardened XML read boundary for externally-authored e-invoice documents.
Every byte parsed here arrives from outside the host: an operator’s attachment, a supplier’s emailed invoice, a payload embedded in a PDF. The document is therefore treated as hostile input, and the parse is bounded on all four axes an XML reader can be attacked on.
Entity resolution and external DTD loading are disabled, which is what
defusedxmlis for and why this module exists rather than each parser reaching forElementTreedirectly. An XXE probe cannot read a local file or open a network connection.Payload size is bounded before parsing begins, so a multi-gigabyte document is refused rather than buffered.
Nesting depth is bounded after parsing, which is the residual billion-laughs-adjacent risk once entity expansion is already off: a deeply nested document can still exhaust the recursion budget of a naive walker.
defusedxml is already a declared [project.dependencies] entry, so exact
structured reading costs no new dependency, no model, no GPU and no extra –
which is what lets it live in the deterministic core rather than behind the
inference boundary.
- local_tag_name(tag)[source]¶
Return an XML tag without its namespace prefix.
ElementTree reports a namespaced tag as
{uri}local. Three parsers each carried this strip, which meant three places decided what a tag’s local name is.
- MAX_XML_PAYLOAD_BYTES¶
Largest e-invoice payload accepted. Two orders of magnitude above any real EN16931 or Facturae document, so it refuses abuse without refusing a genuine invoice carrying embedded attachments.
- MAX_XML_DEPTH¶
Deepest element nesting accepted. EN16931 and Facturae both bottom out well under 20; 100 leaves generous headroom while still bounding a walker.
- exception EInvoiceXmlParseError(message=None, *, context=None, translated_message=None)[source]¶
Bases:
CadrumoErrorRaised when an e-invoice XML payload is refused at the read boundary.
Deliberately a refusal rather than a partial result. A structured reader that returned half a record on malformed input would be worse than a model: it would look exact while being wrong.
CadrumoErrorbinds the refusal to the error registry, so an operator receives a stable code and translated message. XML parsing is not a Pydantic callback, so the adapter raises this registered type directly rather than leaking a builtin validation base.- Parameters:
- Return type:
None
- code¶
- parse_hardened_xml(payload)[source]¶
Parse
payloadwith entity resolution and external DTDs disabled.- Parameters:
payload (
bytes) – Raw document bytes from outside the host.- Return type:
- Returns:
The parsed root
Element.- Raises:
EInvoiceXmlParseError – If the payload is empty, exceeds
MAX_XML_PAYLOAD_BYTES, is not well-formed XML, resolves a forbidden entity, or nests deeper thanMAX_XML_DEPTH.