From 261466a2a816779a2aea70d263f448c2eb516b15 Mon Sep 17 00:00:00 2001 From: Mason Huang Date: Thu, 2 Jul 2026 21:58:11 +0800 Subject: [PATCH] fix: escape docs map heading markup --- docs/docs_map.md | 38 +++++++++++++------------- scripts/generate-docs-map.mjs | 14 ++++++++-- test/scripts/generate-docs-map.test.ts | 13 +++++++++ 3 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 test/scripts/generate-docs-map.test.ts diff --git a/docs/docs_map.md b/docs/docs_map.md index 5456f11536e..5ae113e490c 100644 --- a/docs/docs_map.md +++ b/docs/docs_map.md @@ -289,7 +289,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - Route: /channels/channel-routing - Headings: - - H1: Channels & routing + - H1: Channels & routing - H2: Key terms - H2: Outbound target prefixes - H2: Session key shapes (examples) @@ -1226,7 +1226,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H3: agents bindings - H3: agents bind - H3: agents unbind - - H3: agents delete + - H3: agents delete <id> - H2: Identity files - H2: Set identity - H2: Related @@ -1418,13 +1418,13 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H1: openclaw devices - H2: Commands - H3: openclaw devices list - - H3: openclaw devices remove + - H3: openclaw devices remove <deviceId> - H3: openclaw devices clear --yes [--pending] - H3: openclaw devices approve [requestId] [--latest] - H2: Paperclip / openclawgateway first-run approval - - H3: openclaw devices reject - - H3: openclaw devices rotate --device --role [--scope ] - - H3: openclaw devices revoke --device --role + - H3: openclaw devices reject <requestId> + - H3: openclaw devices rotate --device <id> --role <role> [--scope <scope...>] + - H3: openclaw devices revoke --device <id> --role <role> - H2: Common options - H2: Notes - H2: Token drift recovery checklist @@ -1506,7 +1506,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H3: gateway status - H3: gateway probe - H4: Remote over SSH (Mac app parity) - - H3: gateway call + - H3: gateway call <method> - H2: Manage the Gateway service - H3: Install with a wrapper - H2: Discover gateways (Bonjour) @@ -1747,11 +1747,11 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H3: JSONL - H3: YAML - H2: Subcommand reference - - H3: resolve - - H3: find - - H3: set - - H3: validate - - H3: emit + - H3: resolve <oc-path> + - H3: find <pattern> + - H3: set <oc-path> <value> + - H3: validate <oc-path> + - H3: emit <file> - H2: Exit codes - H2: Output mode - H2: Notes @@ -2039,12 +2039,12 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H3: wiki status - H3: wiki doctor - H3: wiki init - - H3: wiki ingest - - H3: wiki okf import + - H3: wiki ingest <path-or-url> + - H3: wiki okf import <path> - H3: wiki compile - H3: wiki lint - - H3: wiki search - - H3: wiki get + - H3: wiki search <query> + - H3: wiki get <lookup> - H3: wiki apply - H3: wiki bridge import - H3: wiki unsafe-local import @@ -4492,7 +4492,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H3: Volume (required) - H3: Variables - H2: Connect a channel - - H2: Backups & migration + - H2: Backups & migration - H2: Next steps ## install/raspberry-pi.md @@ -5129,7 +5129,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - Route: /platforms/mac/voicewake - Headings: - - H1: Voice Wake & Push-to-Talk + - H1: Voice Wake & Push-to-Talk - H2: Requirements - H2: Modes - H2: Runtime behavior (wake-word) @@ -8544,7 +8544,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H3: 3.6 Discovery (AML.TA0008) - H4: T-DISC-001: Tool Enumeration - H4: T-DISC-002: Session Data Extraction - - H3: 3.7 Collection & Exfiltration (AML.TA0009, AML.TA0010) + - H3: 3.7 Collection & Exfiltration (AML.TA0009, AML.TA0010) - H4: T-EXFIL-001: Data Theft via webfetch - H4: T-EXFIL-002: Unauthorized Message Sending - H4: T-EXFIL-003: Credential Harvesting diff --git a/scripts/generate-docs-map.mjs b/scripts/generate-docs-map.mjs index 84fe3c571e8..0e591e95b0b 100644 --- a/scripts/generate-docs-map.mjs +++ b/scripts/generate-docs-map.mjs @@ -84,14 +84,20 @@ function stripFrontmatter(raw) { return raw; } +function escapeMarkdownHtmlText(value) { + return value.replace(/&/gu, "&").replace(//gu, ">"); +} + function cleanHeadingText(value) { - return value + const normalized = value .replace(/\s+#+\s*$/u, "") - .replace(/<[^>]+>/gu, "") .replace(/\[([^\]]+)\]\([^)]*\)/gu, "$1") .replace(/[*_~`]/gu, "") .replace(/\s+/gu, " ") .trim(); + // Docs map is Markdown consumed by humans and agents. Escape HTML instead of + // trying to strip tags so malformed source headings cannot reintroduce markup. + return escapeMarkdownHtmlText(normalized); } function extractHeadings(raw) { @@ -198,3 +204,7 @@ const isMain = process.argv[1] ? fileURLToPath(import.meta.url) === process.argv if (isMain) { main(); } + +export const testing = { + cleanHeadingText, +}; diff --git a/test/scripts/generate-docs-map.test.ts b/test/scripts/generate-docs-map.test.ts new file mode 100644 index 00000000000..504b5af0b38 --- /dev/null +++ b/test/scripts/generate-docs-map.test.ts @@ -0,0 +1,13 @@ +import { describe, expect, it } from "vitest"; +import { testing } from "../../scripts/generate-docs-map.mjs"; + +describe("generate docs map", () => { + it("renders heading HTML as text", () => { + expect(testing.cleanHeadingText("`API` ")).toBe( + "API <script>alert(1)</script>", + ); + expect(testing.cleanHeadingText("ipt>alert(1)")).toBe( + "<scr<script>ipt>alert(1)</script>", + ); + }); +});