diff --git a/docs/docs.json b/docs/docs.json index 07a88de39f7..98c88e0177c 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1242,7 +1242,6 @@ "group": "Security", "pages": [ "security/formal-verification", - "security/README", "security/THREAT-MODEL-ATLAS", "security/CONTRIBUTING-THREAT-MODEL" ] @@ -1598,7 +1597,6 @@ "zh-CN/tools/apply-patch", "zh-CN/brave-search", "zh-CN/perplexity", - "zh-CN/tools/diffs", "zh-CN/tools/elevated", "zh-CN/tools/exec", "zh-CN/tools/exec-approvals", diff --git a/docs/security/README.md b/docs/security/README.md deleted file mode 100644 index 2a8b5f45410..00000000000 --- a/docs/security/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# OpenClaw Security & Trust - -**Live:** [trust.openclaw.ai](https://trust.openclaw.ai) - -## Documents - -- [Threat Model](/security/THREAT-MODEL-ATLAS) - MITRE ATLAS-based threat model for the OpenClaw ecosystem -- [Contributing to the Threat Model](/security/CONTRIBUTING-THREAT-MODEL) - How to add threats, mitigations, and attack chains - -## Reporting Vulnerabilities - -See the [Trust page](https://trust.openclaw.ai) for full reporting instructions covering all repos. - -## Contact - -- **Jamieson O'Reilly** ([@theonejvo](https://twitter.com/theonejvo)) - Security & Trust -- Discord: #security channel diff --git a/scripts/docs-link-audit.mjs b/scripts/docs-link-audit.mjs index 7a1f60984cd..2b9bb91de16 100644 --- a/scripts/docs-link-audit.mjs +++ b/scripts/docs-link-audit.mjs @@ -113,6 +113,41 @@ function resolveRoute(route) { return { ok: routes.has(current), terminal: current }; } +/** @param {unknown} node */ +function collectNavPageEntries(node) { + /** @type {string[]} */ + const entries = []; + if (Array.isArray(node)) { + for (const item of node) { + entries.push(...collectNavPageEntries(item)); + } + return entries; + } + + if (!node || typeof node !== "object") { + return entries; + } + + const record = /** @type {Record} */ (node); + if (Array.isArray(record.pages)) { + for (const page of record.pages) { + if (typeof page === "string") { + entries.push(page); + } else { + entries.push(...collectNavPageEntries(page)); + } + } + } + + for (const value of Object.values(record)) { + if (value !== record.pages) { + entries.push(...collectNavPageEntries(value)); + } + } + + return entries; +} + const markdownLinkRegex = /!?\[[^\]]*\]\(([^)]+)\)/g; /** @type {{file: string; line: number; link: string; reason: string}[]} */ @@ -221,6 +256,22 @@ for (const abs of markdownFiles) { } } +for (const page of collectNavPageEntries(docsConfig.navigation || [])) { + checked++; + const route = normalizeRoute(page); + const resolvedRoute = resolveRoute(route); + if (resolvedRoute.ok) { + continue; + } + + broken.push({ + file: "docs.json", + line: 0, + link: page, + reason: `navigation page not published (terminal: ${resolvedRoute.terminal})`, + }); +} + console.log(`checked_internal_links=${checked}`); console.log(`broken_links=${broken.length}`);