feat(editor): work-item descriptions store sanitised HTML only; pages store the validated triple; hardened sanitiser
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 5/5
- 预计耗时
- 一周以上
- 新手友好度
- 32/100
调研方向
Start by reading the sanitizer in crates/thrust-editor-doc/src/sanitize.rs, its tests in crates/thrust-editor-doc/tests/sanitize.rs, and the migration and contract references named in the issue. Then trace the work item write path and page fallback write path, keeping the blocked-by #44 dependency in view. Done means the acceptance tests pass, the page binary validation rejects invalid Yjs data, the migration stores only the specified work-item fields, and the listed deviations and questions are recorded.
由索引模型根据 Issue 内容生成。
描述
Context
The slice stores a work item's description as unsanitised text (crates/thrust-adapters-postgres/migrations/0001_init.sql:33; crates/thrust-contracts/src/lib.rs:97, :214; crates/thrust-core/src/lib.rs:260). The sanitiser exists only in the spike crate thrust-editor-doc, behind its sanitize feature, and only thrust-editor-worker depends on it. It provides plane_builder(), Plane's nh3 allow-list (crates/thrust-editor-doc/src/sanitize.rs:100-115); hardened_builder(), which adds value filters (:167-177); validate_binary_data (:208-233); and strip_tags (:235-237). Sanitizer::default() and validate_html_content both use the Plane builder (:192, :197-200). ADR-0012 (accepted in round 27) stores client html, json and binary verbatim at P0 (adrs/ui/0012-editor-and-i18n-reuse.md:33), as decided under Q-F5.1 in round 11 (QUESTIONS.md:153).
Problem
- FR-14, from spike 0006: work-item descriptions carry no binary (v1 returns it null in 64 of 64;
research/0008§2.1, line 42). The v1 serializer excludesdescription_json(apps/api/plane/api/serializers/issue.py:73), and the web editor initialises fromdescription_html(apps/web/core/components/editor/rich-text/description-input/root.tsx:239). Only the page fallback path builds all three forms (apps/web/core/hooks/use-page-fallback.ts). - Storing client JSON next to sanitised HTML therefore creates two sources of truth, one of them unsanitised.
- FR-23: the hardened config neutralises 125 of 125 executable payloads, where Plane's allow-list neutralises 116, and it leaves all 195 editor documents unchanged. Plane's allow-list changes 66 of the 195 for exactly two reasons: it strips
issue-embed-component(5 documents) and rewritesrel(61) (research/0008§7, lines 217-229). - At P1 the Rust converter derives the binary from HTML (§8).
Proposal
- Work items store
description_html(sanitised) anddescription_stripped(strip_tagsof the sanitised HTML). There is nodescription_jsonordescription_binarycolumn at P0. Compat and v1 writes acceptdescription_jsonand discard it. At P1,thrust-editor-docderives JSON and the binary on first collab open. - Pages store the triple the fallback path sends. The HTML is sanitised. The binary is base64-decoded and checked with
validate_binary_data, as Plane'sPageBinaryUpdateSerializerdoes (apps/api/plane/app/serializers/page.py:180-198), and also checked to decode withyrs. Plane does not do that last check, so record it with the deviations below. Pages are an M3 screen, so this half lands with the pages work. - Sanitiser changes:
- Make the hardened builder the default.
- Allow
issue-embed-componentand its five attributes. - Preserve
rel(turn off ammonia'slink_reland allowrelona). - Accept that ammonia 4.x output is not byte-identical to nh3's 4.0.0.
- Sanitise in the use-case layer, so compat and v1 share one path, and record the schema version (ADR-0012).
- Record deviations D-016 to D-020 (handoff A4.4). Build no browser-flavour renderer (Q-0012.4).
Acceptance criteria
- The migration gives work items
description_htmlanddescription_stripped, and neitherdescription_jsonnordescription_binary. - A contract test sends one payload of each of the nine classes that survive Plane's allow-list (
research/0008§7, line 225) through create and update, and reads every one back neutralised. Control: withplane_builder()as the default, the test fails. -
allow_list_preservation_of_editor_html(crates/thrust-editor-doc/tests/sanitize.rs:15-64) asserts 195 of 195 parse-equal under the new allow-list instead of only printing counts. Control: underplane_builder()it fails (129 of 195). - A page write with a truncated or non-Yjs binary gets a 400, and a valid fallback triple is stored.
-
DEVIATIONS.mdhas D-016 to D-020, and Q-0012.2, Q-0012.4, Q-F5.1 and Q-0061.4 are answered.
References
- Review: .agents/plans/contrail/reviews/2026-10-19-fable-architecture-review.md (FR-14, FR-23)
research/0008-editor-conversions.md§2.1, §5 rows 7 and 8, §5.3, §7, §8, §11- ADR-0012 (
:33; round-29 note), ADR-0061 (round-29 note); DEVIATIONS D-012, C-5, D-016 to D-020 - Q-F5.1, Q-0012.2, Q-0012.4, Q-0061.4
crates/thrust-editor-doc/src/sanitize.rs:14,:100-115,:167-237;tests/sanitize.rs:15-64,:225-243- Plane oracle:
apps/api/plane/api/serializers/issue.py:73;apps/api/plane/app/serializers/page.py:173-198;apps/web/core/components/editor/rich-text/description-input/root.tsx:239 - Beads: plane-byd.6
Blocked by: #44
Finding: FR-14, FR-23
- 主要语言
- Rust
- 星标
- 0
- 派生
- 0
- 平均合并
- 1 小时 35 分钟
- 30 天内合并 PR
- 67
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
aRustyDev/thrust 的其他 Issue
-
area:process prio:p1 type:security
难度 4/5 3-5 天 新手友好度 48/100
维护者通常 1 天内回复
-
area:process bug prio:p1
难度 4/5 3-5 天 新手友好度 38/100
维护者通常 1 天内回复
-
area:process prio:p1
难度 4/5 3-5 天 新手友好度 55/100
维护者通常 1 天内回复
-
area:process prio:p1
难度 4/5 1-2 天 新手友好度 55/100
维护者通常 1 天内回复
-
area:process prio:p1
难度 4/5 3-5 天 新手友好度 56/100
维护者通常 1 天内回复
相似的 Issue
-
yara-x fails to build with rsa 0.10.0: unresolved import rsa::Pkcs1v15Sign可能已有人在做 @CfirTsabari 今天认领。 未关闭
难度 1/5 1 小时以内 新手友好度 87/100
VirusTotal/yara-x#865 ·
维护者通常 1 天内回复
-
good first issue help wanted program
难度 2/5 1-3 小时 新手友好度 83/100
hffgzktbcc-blip/ounce-core#297 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
nautechsystems/nautilus_trader#5631 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 69/100
bytecodealliance/rustix#1736 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
longbridge/gpui-kit#3871 ·
维护者通常 1 天内回复