openclaw/scripts/check-webhook-auth-body-order.mts
Peter Steinberger 799ddbd35d
refactor(comments): deslop production narration
## What Problem This Solves

Production code still carries duplicated narration over function names, types, branches and CSS selectors. Some of that prose has drifted: Zalo polling is described as development-only even though it is the default production route, and a joined hook helper is called fire-and-forget.

## User Impact

No user-visible behavior changes. Runtime logic, templates, CSS declarations, configuration, persisted state, wire formats, public API documentation, licenses and lint-suppression reasons remain intact.

## Why This Change Was Made

This maintainer-requested cleanup removes redundant internal helper/registrar summaries, repeated section labels, and obsolete inline font-size history. Existing declarations and shared owners already express these facts; no new abstraction is needed. Comments explaining authority, lifecycle, ordering, cleanup, platform constraints, dependencies and public contracts stay.

The measured reduction is 696 net production/tooling lines: 604 standalone comment lines and 92 adjacent blank lines, plus 59 inline comment removals without net line savings. No tests or generated files changed. This is a bounded contextual sweep, not a claim of exhaustive repository coverage; the local census records exact findings, retained candidates, and unread files. Filename-header cleanup from #161768 is excluded.

## Evidence

Independent review completed; all accepted documentation findings were addressed by restoring base comments. The remaining changed files are byte-identical to the reviewed and remotely frozen candidate.

Blacksmith Testbox validation:
- Parser comparison: identical non-comment TypeScript tokens and CSS structure.
- Both import-cycle checks: 0 cycles.
- Focused existing tests: 40 Vitest shards passed (521.71 seconds).
- Plugin contracts: 48 files / 1,153 tests passed.
- Plugin, source-to-extension, and SDK/package import-boundary checks passed.
- Feishu asset hook check: no build hooks; no plugin browser/control-UI source changed.

SDK API comparison passed with no API changes. The full changed-file gate passed remotely. The lowered-threshold duplicate census (12 lines / 80 tokens) completed; its raw 155 records include deliberate probe/fixture matches and are not claimed as removable production code. No tests were added or changed.

Public JSDoc was audited independently: the SDK API comparison strips comments, while shipped declarations can preserve them, so API-shape equality alone would not prove documentation preservation.


### Inherited hosted CI failure

Exact-head [CI run 36815106181](https://github.com/openclaw/openclaw/actions/runs/36815106181) tested `ff26a4c05d3b41d25477df41cb94010c6cac5cb0` merged with main `75d1f82c18`. The only failing test job was `checks-node-compact-small-19`: `test/helpers/openclaw-test-instance.acquisition.test.ts:33`, “keeps an absent Gateway unreachable while retaining its port claims,” expected `free` but received `busy`. The other failure is the aggregate CI gate. This attempt has 84 successful jobs, 16 skipped jobs, and 88 collateral cancellations; cancelled coverage is not counted as passing.

The identical assertion and error were independently verified in [job 110052175838](https://github.com/openclaw/openclaw/actions/runs/36763489663/job/110052175838), the latest attempt (1) for unrelated PR #162070's final head `d07a6981d4`. The acquisition test, instance helper, cleanup wrapper, isolated-state writer, port allocator, claim owner, claim-lock owner and TCP probe are byte-identical between that head and this PR. No changed file participates in the failing acquisition/probe path. The failure precedes Gateway startup; the logs do not identify the competing listener, so no root-cause repair is claimed.

Landing uses the maintainer-authorized inherited-failure exception pinned to this exact head, backed by the passing remote gates above. The fixture defect remains with the main-CI coordinator. No workflow rerun, test weakening, timeout increase, or source repush was used to obtain green. GitHub's GraphQL writer rejected auto-merge because its quota was exhausted; the request was reconciled as absent before selecting the supported REST squash path.
2026-09-30 22:28:36 -07:00

61 lines
2.1 KiB
TypeScript

#!/usr/bin/env node
// Ensures webhook handlers authenticate before reading request bodies.
import path from "node:path";
import * as ts from "typescript/unstable/ast";
import { bundledPluginCallsite, bundledPluginFile } from "./lib/bundled-plugin-paths.mjs";
import { runCallsiteGuard } from "./lib/callsite-guard.mts";
import {
collectCallExpressionLines,
runAsScript,
unwrapExpression,
} from "./lib/ts-guard-utils.mts";
const sourceRoots = ["extensions"];
const enforcedFiles = new Set([
bundledPluginFile("feishu", "src/monitor.transport.ts"),
bundledPluginFile("googlechat", "src/monitor.ts"),
bundledPluginFile("zalo", "src/monitor.webhook.ts"),
]);
const blockedCallees = new Set(["readJsonBodyWithLimit", "readRequestBodyWithLimit"]);
const allowedCallsites = new Set([
// Feishu signs the exact wire body, so this handler must read raw bytes before parsing JSON.
bundledPluginCallsite("feishu", "src/monitor.transport.ts", 199),
]);
function getCalleeName(expression: ts.Expression): string | null {
const callee = unwrapExpression(expression);
if (ts.isIdentifier(callee)) {
return callee.text;
}
if (ts.isPropertyAccessExpression(callee)) {
return callee.name.text;
}
return null;
}
function findBlockedWebhookBodyReadLines(
_content: string,
_fileName: string,
sourceFile: ts.SourceFile,
): number[] {
return collectCallExpressionLines(sourceFile, (node) => {
const calleeName = getCalleeName(node.expression);
return calleeName && blockedCallees.has(calleeName) ? node.expression : null;
});
}
async function main() {
await runCallsiteGuard({
importMetaUrl: import.meta.url,
sourceRoots,
findCallLines: findBlockedWebhookBodyReadLines,
skipRelativePath: (relPath) => !enforcedFiles.has(relPath.replaceAll(path.sep, "/")),
allowCallsite: (callsite) => allowedCallsites.has(callsite),
header: "Found forbidden low-level body reads in auth-sensitive webhook handlers:",
footer:
"Use plugin-sdk webhook guards (`readJsonWebhookBodyOrReject` / `readWebhookBodyOrReject`) with explicit pre-auth/post-auth profiles.",
});
}
runAsScript(import.meta.url, main);