forked from ChelseaKR/habitable
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_pdf.py
More file actions
129 lines (108 loc) · 5.06 KB
/
Copy pathtest_pdf.py
File metadata and controls
129 lines (108 loc) · 5.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright 2026 Chelsea Kelly-Reif
"""The packet PDF carries basic accessibility hints (toward PDF/UA)."""
from __future__ import annotations
from collections.abc import Callable
from pathlib import Path
from habitable.capture import capture
from habitable.packet import build_packet
from habitable.tsa import LocalRfc3161TSA
from habitable.vault import Vault
def test_packet_pdf_has_accessibility_markers(
make_vault: Callable[..., Vault],
make_jpeg: Callable[..., Path],
local_tsa: LocalRfc3161TSA,
tmp_path: Path,
) -> None:
vault = make_vault()
issue = vault.document.add_issue(category="mold", title="Mold", issue_id="i1")
capture(vault, make_jpeg(), issue_id=issue, tsa=local_tsa)
out = tmp_path / "packet"
build_packet(vault, out, generated_at="2026-01-02T00:10:00Z")
pdf = (out / "packet.pdf").read_bytes()
assert pdf.startswith(b"%PDF-")
# Declares the document language and asks viewers to show the title, not the
# file name — basic PDF/UA hygiene (full tagging is tracked in the ACR).
assert b"/Lang" in pdf
assert b"/ViewerPreferences" in pdf
assert b"/DisplayDocTitle" in pdf
# A navigable outline (bookmarks) for headings.
assert b"/Outlines" in pdf
def test_pdf_points_to_the_accessible_html_rendering() -> None:
"""Per ADR 0004, packet.html is the conformant accessible rendering and the PDF a
print convenience; the PDF disclaimer must direct a reader who needs an accessible
record to packet.html. (PDF body text is stream-encoded, so we assert the renderer's
disclaimer copy rather than searching the compressed bytes.)"""
from habitable.pdf import _PACKET_DISCLAIMER
assert "packet.html" in _PACKET_DISCLAIMER
assert "not legal advice" in _PACKET_DISCLAIMER # the existing copy is preserved
def _with_config(vault: Vault, **kwargs: object) -> None:
from habitable.config import Config
base = {
"language": vault.config.language,
"timestamp_authorities": vault.config.timestamp_authorities,
"packet_template": vault.config.packet_template,
}
base.update(kwargs)
vault.config = Config(**base) # type: ignore[arg-type]
def test_packet_bundle_includes_template_wording(
make_vault: Callable[..., Vault],
make_jpeg: Callable[..., Path],
local_tsa: LocalRfc3161TSA,
tmp_path: Path,
) -> None:
from habitable.config import PacketTemplate
vault = make_vault()
# Jurisdiction wording is presentation only; it lives in the (signed) bundle.
# (PDF text is encoded in streams and not byte-findable, so we assert the data
# layer here; PDF rendering is covered by the build succeeding.)
_with_config(
vault,
packet_template=PacketTemplate(
header="Filed under STATE habitability law", footer="By the union"
),
)
issue = vault.document.add_issue(category="mold", issue_id="i1")
capture(vault, make_jpeg(), issue_id=issue, tsa=local_tsa)
out = tmp_path / "packet"
result = build_packet(vault, out, generated_at="2026-01-02T00:10:00Z")
bundle = result.bundle_path.read_bytes()
assert b"Filed under STATE habitability law" in bundle
assert b"By the union" in bundle
assert result.pdf_path is not None and result.pdf_path.stat().st_size > 1000
def test_pdf_escapes_active_markup_in_template(
make_vault: Callable[..., Vault],
make_jpeg: Callable[..., Path],
local_tsa: LocalRfc3161TSA,
tmp_path: Path,
) -> None:
"""A hostile <img> in a packet template must NOT be parsed as markup.
ReportLab would otherwise open a local path or fetch a URL at build time. A
reference to a nonexistent file would raise during rendering if it were parsed
as an image; escaped, it is inert text and the build succeeds.
"""
from habitable.config import PacketTemplate
vault = make_vault()
poison = '<img src="/no/such/file/should-not-be-opened.png"/>'
_with_config(vault, packet_template=PacketTemplate(header=poison, footer=poison))
issue = vault.document.add_issue(category="mold", issue_id="i1")
capture(vault, make_jpeg(), issue_id=issue, tsa=local_tsa)
out = tmp_path / "packet"
result = build_packet(vault, out, generated_at="2026-01-02T00:10:00Z") # must not raise
assert result.pdf_path is not None and result.pdf_path.exists()
# It is stored as inert data (a quote-free fragment survives canonical JSON).
assert b"should-not-be-opened.png" in result.bundle_path.read_bytes()
def test_pdf_declares_configured_language(
make_vault: Callable[..., Vault],
make_jpeg: Callable[..., Path],
local_tsa: LocalRfc3161TSA,
tmp_path: Path,
) -> None:
vault = make_vault()
_with_config(vault, language="es")
issue = vault.document.add_issue(category="moho", issue_id="i1")
capture(vault, make_jpeg(), issue_id=issue, tsa=local_tsa)
out = tmp_path / "packet"
result = build_packet(vault, out, generated_at="2026-01-02T00:10:00Z")
assert b'"language":"es"' in result.bundle_path.read_bytes()
assert b"/Lang" in (out / "packet.pdf").read_bytes()