mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-11 09:27:41 +00:00
fix(posting-guard): match hidden CSS declaration names (#717)
* fix(posting-guard): distinguish transparent text from decorations * fix(posting-guard): anchor all hidden-style property names * test(posting-guard): clarify browser style calibration cases * docs(changelog): reference posting style fix PR 717 * fix(posting-guard): keep off-screen margins hidden once property names are anchored The unanchored pattern caught margin-left/margin-top: -9999px only as a suffix of left/top. Anchoring the names would have lost that, so list the margin forms explicitly and pin them with a test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Mads Lorentzen <madslorentzen17@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2 files changed
+35
-2
No files matched your search
@@ -605,6 +605,39 @@ class Calibration(GuardFixture):
|
||||
# href targets are attributes, not text: hidden nav links are not "hidden URLs".
|
||||
self.assertEqual(self.findings_of(out)["hidden_urls"], [])
|
||||
|
||||
def test_decoration_and_custom_properties_do_not_hide_visible_posting_text(self):
|
||||
# These declarations are serialized by the browser after assigning the
|
||||
# DOM style properties; each retains black, visible text.
|
||||
styles = [f"{name}: transparent" for name in ("background-color", "border-color", "text-decoration-color")]
|
||||
styles += ["stroke-opacity: 0", "--opacity: 0", "--display: none"]
|
||||
for style in styles:
|
||||
with self.subTest(style=style):
|
||||
page = self.write("posting.html", (
|
||||
f'<article style="color: black; {style};">'
|
||||
'Software Engineer: Python and SQL experience</article>'
|
||||
'<article style="color: transparent;">Hidden content</article>'
|
||||
))
|
||||
code, out, err = self.run_main("--in", str(page), "--html", "--json")
|
||||
self.assertEqual(code, 0, err)
|
||||
self.assertIn("Software Engineer: Python and SQL experience", self.text_of(out))
|
||||
self.assertNotIn("Hidden content", self.text_of(out))
|
||||
self.assertEqual(self.findings_of(out)["hidden_blocks"], ["Hidden content"])
|
||||
|
||||
def test_offscreen_margins_still_hide_once_names_are_anchored(self):
|
||||
# Anchoring the property names must not lose the off-screen margin
|
||||
# trick, which the unanchored pattern only caught as a suffix of "left".
|
||||
for style in ("margin-left: -9999px", "position: absolute; margin-top: -10000px"):
|
||||
with self.subTest(style=style):
|
||||
page = self.write("posting.html", (
|
||||
'<article>Software Engineer: Python and SQL experience</article>'
|
||||
f'<article style="{style};">Hidden content</article>'
|
||||
))
|
||||
code, out, err = self.run_main("--in", str(page), "--html", "--json")
|
||||
self.assertEqual(code, 0, err)
|
||||
self.assertIn("Software Engineer: Python and SQL experience", self.text_of(out))
|
||||
self.assertNotIn("Hidden content", self.text_of(out))
|
||||
self.assertEqual(self.findings_of(out)["hidden_blocks"], ["Hidden content"])
|
||||
|
||||
def test_leading_bom_is_encoding_noise(self):
|
||||
code, out, err = self.run_main("--text", "--json", stdin_text="Plain posting.")
|
||||
self.assertTrue(out.startswith("posting_guard: clean"), out.splitlines()[0])
|
||||
|
||||
@@ -97,14 +97,14 @@ VARIATION = re.compile("[︀-️\U000E0100-\U000E01EF]")
|
||||
VARIATION_RUN = re.compile("[︀-️\U000E0100-\U000E01EF]{2,}")
|
||||
|
||||
HIDDEN_STYLE = re.compile(
|
||||
r"display\s*:\s*none"
|
||||
r"(?:^|;)\s*(?:display\s*:\s*none"
|
||||
r"|visibility\s*:\s*hidden"
|
||||
r"|opacity\s*:\s*0(?![.\d]*[1-9])"
|
||||
r"|font-size\s*:\s*0(?:\.0+)?(?:px|pt|em|rem|%)?(?![\d.])"
|
||||
r"|color\s*:\s*transparent"
|
||||
r"|clip\s*:\s*rect\(\s*0"
|
||||
r"|clip-path\s*:\s*inset\(\s*100%"
|
||||
r"|(?:left|top|text-indent)\s*:\s*-\d{4,}px",
|
||||
r"|(?:(?:margin-)?(?:left|top)|text-indent)\s*:\s*-\d{4,}px)",
|
||||
re.I,
|
||||
)
|
||||
PRESTRIP = re.compile(r"<!DOCTYPE[^>]*>|<\?[^>]*\?>", re.I)
|
||||
|
||||
Reference in new issue
Block a user