Skip to content

docx_io split - Slice 2: extract xml_utils.py (_safe_fromstring) #73

Description

@LegalMarc

Design doc (read in full first): docs/design/docx_io_package_split.md — §2, §4 Slice 2.

Slice 2 of 5 of the docx_io.py package split. One function, no state — extracting it early unblocks every later slice from re-deciding where it lives.

Scope

Move _safe_fromstring() (docx_io.py:18) into marcut/docx/xml_utils.py. This is the lxml parser configured with resolve_entities=False (XXE hardening) used by nearly every other section of the module.

Re-export it from docx_io.py so existing references (incl. tests/test_security.py:4from marcut.docx_io import _safe_fromstring) keep working.

Non-negotiable requirements

  • XXE hardening must be preserved exactly. resolve_entities=False (and any other hardening flags on the parser) must survive the move unchanged. tests/test_security.py's external-entity payload test must still pass — the external entity must not resolve.
  • Use the package name agreed in Slice 1 (#72).

Acceptance criteria

  • _safe_fromstring() moved to marcut/docx/xml_utils.py, re-exported from docx_io.py.
  • tests/test_security.py passes unchanged (or with only an import-path edit) — XXE payload still does not resolve.
  • Golden-file harness (#70) diffs to zero.
  • One real marcut redact run diffed against pre-slice baseline → no difference.

Verification loop (design doc §3.3)

  1. PYTHONPATH=src/python python3 -m pytest tests/test_docx_io.py tests/test_metadata_scrubbing.py tests/test_pipeline.py tests/test_url_redaction.py tests/test_failure_scenarios.py tests/test_security.py -q.
  2. Golden-file harness — empty diff.
  3. marcut redact against a sample-files/ fixture, diffed vs baseline.

Plus the standard gate: full pytest -q, swift build, swift test, bash scripts/release_preflight.sh.

Dependencies

Blocked by #70. Independent of the other slices. Follow the package-naming decision from #72.


Land as its own PR; do not combine with other issues in this set. Do not reopen design-spike #25.

Metadata

Metadata

Assignees

No one assigned

    Labels

    afkAutonomous workflow-loop eligible

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions