Sanitize RFC 5545 control characters in TEXT on output (#1712) - #1741
Sanitize RFC 5545 control characters in TEXT on output (#1712)#1741Dmao233 wants to merge 7 commits into
Conversation
|
This pull request did not pass quality checks and AI use is suspected. Please review Contribute and make any necessary amendments. |
|
Profile summary: Full profile |
Documentation build overview
3 files changed± genindex.html± reference/api/icalendar.prop.text.html± _modules/icalendar/prop/text.html |
CIFuzz failed after parse stayed open: dateutil.tzical raised ValueError: unsupported property: RRULE, which was not ignored. AI use: Cursor Grok 4.6 Prompt: Add newly-exposed dateutil parse errors to the fuzzer ignore list after CIFuzz failed on collective#1741.
Parse stays open; leftover CONTROLs are stripped on serialize so NUL cannot reach ICS output. AI use: Cursor Grok 4.6 Prompt: Fix NUL in TEXT values by sanitizing on output per collective#1712.
CIFuzz reached dateutil after parse stayed open; ignore those expected ValueErrors. AI use: Cursor Grok 4.6 Prompt: Add dateutil parse errors to the fuzzer ignore list after CI failed.
e81edf6 to
e3cf05a
Compare
|
Quality bot failed on description length, missing checklist boxes, commit author not matching, and a first commit over 500 chars. Description is back on the template. Commits rewritten as me: It also flags the username Dmao233 for consecutive digits. I cannot change that. |
|
@Dmao233 there's no need to repeat anything from the comments made by automation or in pushed commits. Maintainers receive an email notification for each comment and pushed commit, as well as view the results of CI. We need to do a better job of clarifying that in our contributing documentation, as many new contributors don't understand that AI is incredibly noisy and states the obvious. And there's no need to reply to this comment, as that would be yet more noise, but you can use reactions. Thank you! |
|
@Dmao233 the CI fuzzing check fails. We don't review pull requests until CI checks pass. Would you please take care? Thank you! |
A malformed RRULE key reached to_ical() with a raw LF after parse stayed open. from_parts now strips leftover CR/LF so serialize cannot hit the Contentline assert. AI use: Cursor Grok 4.6 Prompt: Stop CIFuzz AssertionError on unescaped newlines in content lines for collective#1741.
from_parts must keep failing loudly (issue collective#1445). CIFuzz hit that assert on a malformed RRULE; treat only that message as an expected parse/serialize error. AI use: Cursor Grok 4.6 Prompt: Revert silent newline stripping and ignore only the Contentline raw-newline assert in the fuzzer.
|
Fuzzing is green now. |
angatha
left a comment
There was a problem hiding this comment.
Thank you for your contribution. I have some suggestions and questions.
| "mandatory TZOFFSETFROM", # dateutil tzical | ||
| "no timezones defined", # dateutil tzical | ||
| "more than one timezone available", # dateutil tzical | ||
| "Unsupported DTSTART param", # dateutil tzical |
There was a problem hiding this comment.
Why did thouse became a problem now?
| # control character except the horizontal tab may appear in a TEXT value. | ||
| # The line feed, ``\x0a``, is additionally accepted here because it is the | ||
| # result of the escaped sequences ``\N`` and ``\n``. | ||
| UNSAFE_TEXT_CHARS = re.compile(r"[\x00-\x08\x0b-\x1f\x7f]") |
There was a problem hiding this comment.
This is a breaking change. Please keep it.
| _UNSAFE_TEXT_CHARS = re.compile(r"[\x00-\x08\x0b-\x1f\x7f]") | ||
|
|
||
|
|
||
| def _escape_char(text: str | bytes) -> str: |
There was a problem hiding this comment.
Method name and description does not suggest character filtering. Additionally there is _unescape_char in string.py, which should do the inverse. I would prefere another method for that, or you move this to vText.__init__. Then it would also catch to_jcal.
| # CONTROL except HTAB (see :rfc:`5545#section-3.1`). After the line-break | ||
| # escapes below, any remaining CONTROL other than HTAB is stripped so | ||
| # serialized output never contains a raw control character. | ||
| _UNSAFE_TEXT_CHARS = re.compile(r"[\x00-\x08\x0b-\x1f\x7f]") |
There was a problem hiding this comment.
Please rever this and use the constant defined in text.py
| # Contentline.__new__ fails loudly on a raw LF (issue #1445). That is | ||
| # expected for non-TEXT values such as a malformed RRULE; do not treat | ||
| # it as a fuzzer crash. Other asserts still propagate. | ||
| if _CONTENTLINE_NEWLINE_ASSERT in str(e): | ||
| return -1 | ||
| raise |
There was a problem hiding this comment.
Why is this now a problem?
| FORBIDDEN_VALUES = [ | ||
| *FORBIDDEN_CONTROL_CHARS, | ||
| "A\x00B", # NUL from the issue report | ||
| "a\rb", # lone carriage return |
Keep the public UNSAFE_TEXT_CHARS name. Filter in vText.__new__ so to_ical and to_jcal stay clean; leave _escape_char as an escaper. Drop unproven fuzzer ignores. AI use: Cursor Grok 4.6 Prompt: Address angatha review on collective#1741: restore UNSAFE_TEXT_CHARS and move filtering out of _escape_char.
Use a raw docstring for _strip_unsafe_text_chars. Tighten the two remaining fuzzer ignore comments to the proven CIFuzz exceptions. AI use: Cursor Grok 4.6 Prompt: Fix ruff D301 and confirm remaining collective#1741 review items.
) to_unicode leaves UUID/int/None unchanged; Event.new and vUid.new pass those into vText. Coerce to str so construction matches the old str.__new__ behavior. AI use: Cursor Grok 4.6 Prompt: Fix ruff D301 and the 3.14 UUID/int/None AttributeError from vText sanitization. Co-authored-by: CenFangyu <Dmao233@users.noreply.github.com>
|
Addressed in 278d267 and cada72d.
|
Linked issue
Description
#1723 rejects control characters on parse. That still lets round-trip emit NUL, and it fails callers on junk files. nicco asked to keep parse open and emit valid TEXT. This strips leftover CONTROLs on output. Parameter NULs still go into errors.
Checklist
Additional information
I used AI to help draft the patch. I read the issue thread and checked the tests, including the reporter repro.