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:
parent
abcdfa3663
commit
6f32e70c6d
2 changed files with 77 additions and 1 deletions
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue