Add faux-redaction audit (paint-order and colour-aware, fail-closed) (#110)

* Rework faux-redaction audit per maintainer review

- Paint-order aware: a rectangle counts as a cover only when painted
  strictly after the text (positions from the joined content stream).
- Colour-aware: WCAG contrast between text and cover must be below 3.0,
  so page backgrounds, table shading and highlights are not flagged.
- Fail closed: audit_redactions returns Err on undecodable content
  streams (decoded_strict) and malformed /Annots; the operator bound is
  an error, not a silent truncation.
- Graphics state carries across a page's content streams (one joined
  walk); form XObjects still isolate their state at Do.
- Audit-only: the sanitize-for-sharing half is dropped (upstream #162).
- Parity entry marked partial, not shipped.

* Audit: register its layer, add a README, fail closed past 32 nested forms, document what it doesn't check

---------

Co-authored-by: Erick Barraza <ejbarraza1994@gmail.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
ejbarraza
2026-10-11 14:32:33 -04:00
committed by GitHub
co-authored by Erick Barraza Brandon Thomas
parent 0059ed657c
commit 21d5323132
18 changed files with 837 additions and 0 deletions
+12
View File
@@ -5761,6 +5761,18 @@ tools = ["doc_remove_hidden"]
evidence = ["crates/redact/src/tests.rs::hidden_information_is_counted_and_removed", "crates/ui-egui/tests/redact.rs::removing_hidden_information_and_sanitizing", "crates/automation/tests/automation.rs::removing_hidden_information_through_tools"]
notes = "every category, then a full rewrite on save"
[[feature]]
id = "protect.audit-faux-redactions"
title = "Audit: detect faux redactions (opaque covers over extractable text, unapplied marks)"
area = "G"
tier = "P2"
milestone = "M8"
status = "partial"
commands = []
tools = ["doc_audit_redactions"]
evidence = ["crates/audit/src/tests.rs::faux_redaction_is_found", "crates/audit/src/tests.rs::background_before_text_is_not_flagged", "crates/audit/src/tests.rs::light_shading_after_text_is_not_flagged", "crates/audit/src/tests.rs::graphics_state_carries_across_streams", "crates/audit/src/tests.rs::audit_fails_closed_on_undecodable_stream", "crates/audit/src/tests.rs::unapplied_redact_mark_is_found", "crates/automation/tests/automation.rs::auditing_faux_redactions_through_tools"]
notes = "New pdfcraft-audit crate. A filled rectangle (re + fill, opaque) counts as a cover only when painted after the text it overlaps and dark enough to hide it (WCAG contrast < 3.0); page backgrounds, table shading and highlights are not flagged. Graphics state carries across a page's content streams. Fails closed: undecodable content is an error, never a clean bill. Also flags /Redact annotations never applied. CLI: pdfcraft-cli audit (fails when findings exist)."
[[feature]]
id = "protect.remove-hidden-on-close"
title = "Remove hidden information when closing or sending"