Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2020,7 +2020,10 @@ def _splice_attachment_into_body(issue_body: str, attachment: str, cve_id: str)
end_escaped = re.escape(end_marker)
pattern = rf"{begin_escaped}.*?{end_escaped}\n?"
if re.search(pattern, issue_body, re.DOTALL):
new_body = re.sub(pattern, attachment.rstrip("\n") + "\n", issue_body, count=1, flags=re.DOTALL)
# A callable replacement is inserted verbatim; a string would have its
# backslash escapes processed, turning the JSON's ``\n`` into newlines.
replacement = attachment.rstrip("\n") + "\n"
new_body = re.sub(pattern, lambda _: replacement, issue_body, count=1, flags=re.DOTALL)
return new_body.rstrip() + "\n"

# Also tolerate a legacy single-marker attachment that was embedded
Expand Down
18 changes: 18 additions & 0 deletions tools/cve-tool-vulnogram/generate-cve-json/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,24 @@ def test_replaces_existing_attachment_block(self):
assert begin in result
assert end in result

def test_replace_keeps_json_backslash_escapes_verbatim(self):
# Replacing an existing block must not process backslash escapes in
# the new attachment: a JSON ``\n`` inside a string value has to stay
# a two-character escape, or the embedded JSON stops parsing.
begin, end = self._markers()
payload = {
"summary": "First paragraph.\n\nSecond paragraph.",
"path": "C:\\temp\\x",
"group": "keep \\1 literal",
}
json_text = json.dumps(payload, indent=2)
attachment = f"{begin}\n## CVE JSON\n```json\n{json_text}\n```\n{end}\n"
body = f"### Body before\nstuff\n\n{begin}\nOLD CONTENT\n{end}\ntrailing line\n"
result = cve_json._splice_attachment_into_body(body, attachment, self.cve_id)
embedded = result.split("```json\n", 1)[1].split("\n```", 1)[0]
assert embedded == json_text
assert json.loads(embedded) == payload

def test_legacy_single_marker_path(self):
begin, _ = self._markers()
body = f"### Body\n\n{begin}\nleftover legacy content with no end marker\n"
Expand Down