From ed23706e9d843fdeadd2ba40a0b236da4ad33c49 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 26 Aug 2026 01:57:59 -0700 Subject: [PATCH] fix(ci): close CodeQL alerts 1 through 10 --- .github/workflows/commander-multiplatform.yml | 3 ++ .github/workflows/macos-ci.yml | 7 +++- .github/workflows/pages.yml | 1 + .github/workflows/update-homebrew.yml | 3 ++ package.json | 3 +- scripts/build-docs-site.mjs | 6 +-- scripts/docs-site-toc.mjs | 42 +++++++++++++++++++ tests/docs-site-toc.test.mjs | 42 +++++++++++++++++++ 8 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 scripts/docs-site-toc.mjs create mode 100644 tests/docs-site-toc.test.mjs diff --git a/.github/workflows/commander-multiplatform.yml b/.github/workflows/commander-multiplatform.yml index 131da1408..f22e7c0bc 100644 --- a/.github/workflows/commander-multiplatform.yml +++ b/.github/workflows/commander-multiplatform.yml @@ -11,6 +11,9 @@ on: - '.github/workflows/commander-multiplatform.yml' workflow_dispatch: +permissions: + contents: read + jobs: macos-host: runs-on: macos-26 diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 15f9adfe3..eaaf3af3b 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ main ] +permissions: + contents: read + concurrency: group: macos-ci-${{ github.ref }} cancel-in-progress: true @@ -30,7 +33,9 @@ jobs: bun-version: "latest" - name: Docs lint - run: node scripts/docs-lint.mjs + run: | + node scripts/docs-lint.mjs + node --test tests/docs-site-toc.test.mjs - name: Select Xcode 26.6 (if present) or fallback to default run: | diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index f5c40b3d1..e6922845f 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -7,6 +7,7 @@ on: - "docs/**" - "scripts/build-docs-site.mjs" - "scripts/docs-site-assets.mjs" + - "scripts/docs-site-toc.mjs" - ".github/workflows/pages.yml" workflow_dispatch: diff --git a/.github/workflows/update-homebrew.yml b/.github/workflows/update-homebrew.yml index 2358d729c..1d44f9c1d 100644 --- a/.github/workflows/update-homebrew.yml +++ b/.github/workflows/update-homebrew.yml @@ -9,6 +9,9 @@ on: description: 'Version to update (e.g., 2.0.1)' required: true +# Cross-repository dispatch uses only the explicit HOMEBREW_TAP_TOKEN below. +permissions: {} + jobs: update-homebrew-formula: runs-on: ubuntu-latest diff --git a/package.json b/package.json index 4f66f5947..2c85d8226 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,10 @@ "app:restart": "./scripts/restart-peekaboo.sh", "app:install-companion": "./scripts/restart-peekaboo.sh --deployment", "build": "pnpm run build:cli", - "test:safe": "pnpm run test:ambient-state-policy && pnpm run test:guidance && scripts/test-source-provenance.sh && scripts/test-terminal-artifact-env.sh && scripts/test-release-version.sh && scripts/test-read-macho-info-plist.sh && scripts/test-artifact-tree-manifest.sh && scripts/test-controller-source-manifest.sh && scripts/test-atomic-rename-exclusive.sh && scripts/test-terminal-artifact-policy.sh && node scripts/test-terminal-archive-policy.mjs && node scripts/test-terminal-dmg-payload.mjs && scripts/test-terminal-manifest-portability.sh && scripts/test-build-node-runtime-macos.sh && scripts/test-build-playground-artifact.sh && scripts/test-build-terminal-dmg.sh && scripts/test-notarize-terminal-artifact.sh && scripts/test-release-signing-policy.sh && scripts/test-release-package-resolution.sh && scripts/test-release-binary-reuse.sh && scripts/test-codesign-with-retry.sh && scripts/test-sign-release-app.sh && scripts/test-swift-runtime-libraries.sh && scripts/test-create-release-dmg.sh && scripts/test-restart-peekaboo.sh && scripts/test-swiftpm-consumer.sh && node scripts/test-update-appcast-entry.mjs && node --no-warnings scripts/test-chrome-devtools-mcp-contract.mjs && pnpm run test:release-preflight && pnpm run test:background-certification && swift test --package-path Core/PeekabooFoundation && PEEKABOO_INCLUDE_AUTOMATION_TESTS=true PEEKABOO_INCLUDE_AMBIENT_STATE_TESTS=false swift test --package-path Apps/CLI -Xswiftc -DPEEKABOO_SKIP_AUTOMATION --no-parallel", + "test:safe": "pnpm run test:ambient-state-policy && pnpm run test:guidance && pnpm run test:docs-site && scripts/test-source-provenance.sh && scripts/test-terminal-artifact-env.sh && scripts/test-release-version.sh && scripts/test-read-macho-info-plist.sh && scripts/test-artifact-tree-manifest.sh && scripts/test-controller-source-manifest.sh && scripts/test-atomic-rename-exclusive.sh && scripts/test-terminal-artifact-policy.sh && node scripts/test-terminal-archive-policy.mjs && node scripts/test-terminal-dmg-payload.mjs && scripts/test-terminal-manifest-portability.sh && scripts/test-build-node-runtime-macos.sh && scripts/test-build-playground-artifact.sh && scripts/test-build-terminal-dmg.sh && scripts/test-notarize-terminal-artifact.sh && scripts/test-release-signing-policy.sh && scripts/test-release-package-resolution.sh && scripts/test-release-binary-reuse.sh && scripts/test-codesign-with-retry.sh && scripts/test-sign-release-app.sh && scripts/test-swift-runtime-libraries.sh && scripts/test-create-release-dmg.sh && scripts/test-restart-peekaboo.sh && scripts/test-swiftpm-consumer.sh && node scripts/test-update-appcast-entry.mjs && node --no-warnings scripts/test-chrome-devtools-mcp-contract.mjs && pnpm run test:release-preflight && pnpm run test:background-certification && swift test --package-path Core/PeekabooFoundation && PEEKABOO_INCLUDE_AUTOMATION_TESTS=true PEEKABOO_INCLUDE_AMBIENT_STATE_TESTS=false swift test --package-path Apps/CLI -Xswiftc -DPEEKABOO_SKIP_AUTOMATION --no-parallel", "test:ambient-state-policy": "node --test tests/ambient-state-test-policy.test.mjs", "test:guidance": "node --test tests/background-capability-guidance.test.mjs", + "test:docs-site": "node --test tests/docs-site-toc.test.mjs", "test:release-preflight": "node --test tests/release-preflight-contract.test.mjs", "test:background-certification": "scripts/test-background-certification.sh", "test:automation": "PEEKABOO_INCLUDE_AUTOMATION_TESTS=true swift test --package-path Apps/CLI --no-parallel", diff --git a/scripts/build-docs-site.mjs b/scripts/build-docs-site.mjs index 2cbfafc8b..3b49b5b11 100644 --- a/scripts/build-docs-site.mjs +++ b/scripts/build-docs-site.mjs @@ -3,6 +3,7 @@ import fs from "node:fs"; import path from "node:path"; import { css, faviconSvg, js } from "./docs-site-assets.mjs"; +import { renderedHeadingText } from "./docs-site-toc.mjs"; const root = process.cwd(); const docsDir = path.join(root, "docs"); @@ -482,10 +483,7 @@ function tocFromHtml(html) { const re = /([\s\S]*?)<\/h[23]>/g; let m; while ((m = re.exec(html))) { - const text = m[3] - .replace(/]*>.*?<\/a>/, "") - .replace(/<[^>]+>/g, "") - .trim(); + const text = renderedHeadingText(m[3]); items.push({ level: Number(m[1]), id: m[2], text }); } if (items.length < 2) return ""; diff --git a/scripts/docs-site-toc.mjs b/scripts/docs-site-toc.mjs new file mode 100644 index 000000000..205f12431 --- /dev/null +++ b/scripts/docs-site-toc.mjs @@ -0,0 +1,42 @@ +export function renderedHeadingText(html) { + let content = html; + if (content.startsWith('"); + if (anchorEnd >= 0) content = content.slice(anchorEnd + "".length); + } + + // This is renderer-owned HTML. Walk complete tags so removing one cannot expose another tag-like sequence. + let text = ""; + for (let index = 0; index < content.length; ) { + if (content[index] !== "<") { + text += content[index]; + index += 1; + continue; + } + + const tagEnd = renderedTagEnd(content, index + 1); + if (tagEnd < 0) { + text += content.slice(index); + break; + } + index = tagEnd + 1; + } + return text.trim(); +} + +function renderedTagEnd(html, start) { + let quote = null; + for (let index = start; index < html.length; index += 1) { + const char = html[index]; + if (quote) { + if (char === quote) quote = null; + continue; + } + if (char === '"' || char === "'") { + quote = char; + continue; + } + if (char === ">") return index; + } + return -1; +} diff --git a/tests/docs-site-toc.test.mjs b/tests/docs-site-toc.test.mjs new file mode 100644 index 000000000..1c6af30ba --- /dev/null +++ b/tests/docs-site-toc.test.mjs @@ -0,0 +1,42 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; +import test from 'node:test'; +import { fileURLToPath } from 'node:url'; + +import { renderedHeadingText } from '../scripts/docs-site-toc.mjs'; + +const projectRoot = fileURLToPath(new URL('..', import.meta.url)); + +test('heading text ignores quoted tag delimiters', () => { + const heading = '#visible'; + assert.equal(renderedHeadingText(heading), 'visible'); +}); + +test('docs TOC structurally extracts renderer-owned heading text', (t) => { + const fixtureRoot = mkdtempSync(path.join(os.tmpdir(), 'peekaboo-docs-toc-')); + t.after(() => rmSync(fixtureRoot, { recursive: true, force: true })); + mkdirSync(path.join(fixtureRoot, 'docs'), { recursive: true }); + writeFileSync(path.join(fixtureRoot, 'docs', 'index.md'), [ + '# Fixture', + '', + '## **Bold** _emphasis_ [link](https://example.com) `code`', + '', + '### Literal & text', + '' + ].join('\n')); + + const result = spawnSync(process.execPath, [path.join(projectRoot, 'scripts', 'build-docs-site.mjs')], { + cwd: fixtureRoot, + encoding: 'utf8' + }); + assert.equal(result.status, 0, result.stderr || result.stdout); + + const html = readFileSync(path.join(fixtureRoot, '_site', 'index.html'), 'utf8'); + assert.match(html, /