mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-14 14:17:08 +00:00
Add an inline-rendering, versionable html artifact kind
Add an html kind to the artifact generator: it renders a styled HTML report from a stored JSON spec (title + heading/paragraph/list/table/code blocks), producing text/html bytes the sidebar already previews inline in the sandboxed iframe, while keeping the spec as the source of truth so edit and rewrite make real versions. So a single artifact both renders inline and versions conversationally. The renderer is a fixed program fed the spec as data, and every spec text value is HTML-escaped into the output.
This commit is contained in:
1 parent
d573bab4a0
commit
6c8a72c836
3 files changed
+286
-7
No files matched your search
@@ -158,3 +158,84 @@ def test_pdf_renderer_escapes_markup_and_does_not_execute():
|
||||
spec = {"title": payload, "blocks": [{"type": "paragraph", "text": payload}]}
|
||||
out_path = _render_in_process("pdf", spec)
|
||||
assert os.path.getsize(out_path) > 0
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# html kind: schema, renderer injection safety, output escaping
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_validate_accepts_html_spec():
|
||||
spec = {
|
||||
"title": "Report",
|
||||
"blocks": [
|
||||
{"type": "heading", "text": "Intro", "level": 2},
|
||||
{"type": "paragraph", "text": "Body."},
|
||||
{"type": "list", "ordered": True, "items": ["a", "b"]},
|
||||
{"type": "table", "headers": ["h"], "rows": [["c"]]},
|
||||
{"type": "code", "text": "print(1)"},
|
||||
],
|
||||
}
|
||||
assert _tool()._validate("html", spec) is None
|
||||
|
||||
|
||||
def test_validate_rejects_html_unknown_block_key():
|
||||
err = _tool()._validate("html", {"blocks": [{"type": "paragraph", "text": "x", "bogus": 1}]})
|
||||
assert err["status"] == "error"
|
||||
|
||||
|
||||
def test_validate_rejects_html_bad_heading_level():
|
||||
err = _tool()._validate("html", {"blocks": [{"type": "heading", "text": "x", "level": 9}]})
|
||||
assert err["status"] == "error"
|
||||
|
||||
|
||||
def test_html_renderer_does_not_execute_spec_code(capfd, tmp_path):
|
||||
# The renderer json.loads the spec as data; a value that is Python source
|
||||
# must never run. If the program string-interpolated the spec it would.
|
||||
sentinel = tmp_path / "pwned.txt"
|
||||
payload = (
|
||||
f"'''__import__('os').system('echo PWNED > {sentinel}')'''; "
|
||||
"print('SHOULD_NOT_PRINT')"
|
||||
)
|
||||
spec = {"title": payload, "blocks": [{"type": "paragraph", "text": payload}]}
|
||||
out_path = _render_in_process("html", spec)
|
||||
|
||||
captured = capfd.readouterr()
|
||||
assert "SHOULD_NOT_PRINT" not in captured.out
|
||||
assert "PWNED" not in captured.out
|
||||
assert not sentinel.exists()
|
||||
assert os.path.getsize(out_path) > 0
|
||||
|
||||
|
||||
def test_html_renderer_escapes_spec_markup():
|
||||
# Spec text carrying live markup must appear HTML-ESCAPED in the output, so
|
||||
# no raw <script>/<img onerror> tag from spec content reaches the document.
|
||||
script = "<script>alert(1)</script>"
|
||||
img = '<img src=x onerror="alert(2)">'
|
||||
spec = {
|
||||
"title": script,
|
||||
"blocks": [
|
||||
{"type": "paragraph", "text": img},
|
||||
{"type": "heading", "text": "<b>h</b>", "level": 1},
|
||||
{"type": "list", "items": ["<i>x</i>"]},
|
||||
{"type": "table", "headers": ["<u>th</u>"], "rows": [["<em>td</em>"]]},
|
||||
{"type": "code", "text": "</code><script>x</script>"},
|
||||
],
|
||||
}
|
||||
with open(_render_in_process("html", spec), encoding="utf-8") as handle:
|
||||
html_doc = handle.read()
|
||||
|
||||
# No live tag from spec content survives.
|
||||
assert "<script>alert(1)</script>" not in html_doc
|
||||
assert "<img src=x onerror=" not in html_doc
|
||||
assert "<b>h</b>" not in html_doc
|
||||
assert "<i>x</i>" not in html_doc
|
||||
assert "<u>th</u>" not in html_doc
|
||||
assert "<em>td</em>" not in html_doc
|
||||
# The escaped forms are present instead.
|
||||
assert "<script>alert(1)</script>" in html_doc
|
||||
assert "<img src=x onerror=" in html_doc
|
||||
# The fixed structural HTML the renderer emits is intact.
|
||||
assert "<!doctype html>" in html_doc
|
||||
assert "<p>" in html_doc and "</p>" in html_doc
|
||||
assert "<table>" in html_doc and "<pre><code>" in html_doc
|
||||
Reference in new issue
Block a user