1
0
Fork 0

feat(inbox): docx table cells + grouped pptx shapes (stage 2g)

Two structural regions the office extractors missed, no new dependency:
- .docx table cells (they live outside doc.paragraphs);
- grouped .pptx shapes (add_group_shape moves a shape inside the group, so the
  extractor recurses through MSO_SHAPE_TYPE.GROUP to reach it).

Each proven by an injection-in-region REJECT plus a clean-region ADMIT. Tests
310 -> 314.
This commit is contained in:
Kjell Tore Guttormsen 2026-07-07 07:32:10 +02:00
commit 6f32e70c6d
2 changed files with 77 additions and 1 deletions

View file

@ -363,3 +363,62 @@ def test_pptx_notes_detach_proof(tmp_path):
fp = _make_pptx(tmp_path, body="A routine slide.")
_extracted, _result, verdict = receive([fp])
assert verdict == "ADMIT"
# --- slice 2g: office-extractor completeness (no new dep) -------------------
# Two structural regions the earlier slices did not reach: .docx table cells (they
# live outside doc.paragraphs) and grouped .pptx shapes (add_group_shape moves the
# shape inside the group, so only recursion reaches it).
def _docx_with_table(tmp_path, cell_text, name="table.docx"):
from docx import Document
d = Document()
d.add_paragraph("A normal paragraph.")
table = d.add_table(rows=1, cols=2)
table.cell(0, 0).text = "label"
table.cell(0, 1).text = cell_text
fp = tmp_path / name
d.save(str(fp))
return fp
def _pptx_with_grouped_text(tmp_path, text, name="grouped.pptx"):
from pptx import Presentation
from pptx.util import Emu
prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6])
tb = slide.shapes.add_textbox(Emu(0), Emu(0), Emu(1000000), Emu(400000))
tb.text_frame.text = text
slide.shapes.add_group_shape([tb]) # moves tb inside the group (not top-level)
fp = tmp_path / name
prs.save(str(fp))
return fp
def test_docx_table_cell_injection_is_caught(tmp_path):
fp = _docx_with_table(tmp_path, _INJECTION)
_extracted, result, verdict = receive([fp])
assert result.disposition is Disposition.FAIL_SECURE
assert verdict == "REJECT"
def test_clean_docx_table_admits(tmp_path):
fp = _docx_with_table(tmp_path, "a clean value")
_extracted, _result, verdict = receive([fp])
assert verdict == "ADMIT"
def test_pptx_grouped_shape_injection_is_caught(tmp_path):
fp = _pptx_with_grouped_text(tmp_path, _INJECTION)
_extracted, result, verdict = receive([fp])
assert result.disposition is Disposition.FAIL_SECURE
assert verdict == "REJECT"
def test_clean_pptx_grouped_shape_admits(tmp_path):
fp = _pptx_with_grouped_text(tmp_path, "clean grouped text")
_extracted, _result, verdict = receive([fp])
assert verdict == "ADMIT"