Skip to content

Hook-body build gates: @capabilities override dead through os build; require() pattern dead; default build silently bundles forbidden patterns #10678

Description

@baozhoutao

Found by QA run #10663 driving cli.hook-body-extraction-gates at framework 79ebb37. The security net is intact throughout — no forbidden body ever shipped as body.source, and every forbidden/free-identifier hook was still refused under --strict-body. Three defects in the reporting/reachability, not the enforcement:

1. // @capabilities override is unreachable through os build (product/docs gap)

A handler authored in objectstack.config.ts with a first line // @capabilities api.read api.write produces artifact capabilities []. The config loader (config.ts:loadConfigbundle-require → esbuild transformSync{loader:'ts'}) strips // line comments before String(fn) runs, so the override at extract-hook-body.ts:118-131 — documented as working at hook-bodies.mdx:320-327 — never receives the comment. The pin lower-callables.test.ts masks it by feeding raw JS function literals that keep their comment, never exercising the esbuild load path. Fix: move the directive off a // comment (e.g. a real property), or state in docs that it is authorable only in pre-bundled JS; add an os build-level test.

2. require() FORBIDDEN pattern is effectively dead (assertion/coverage gap)

require('node:os') in a TS config is rewritten by esbuild's ESM shim to __require("node:os"), so FORBIDDEN_PATTERNS[/\brequire\s*\(/] (extract-hook-body.ts:35) never matches. The refusal still fires (exit 1) — via the #1876 free-identifier gate naming __require — so enforcement holds, but the require()-specific worded reason the acceptance promises is never emitted for the real authoring path.

3. Default os build silently warn-and-bundles forbidden patterns (header contradiction)

A default (non---strict-body) os build of a hook containing a forbidden pattern exits 0 with no output: lower-callables.ts:63-78 catches the extraction error and falls back to the .mjs bundle; the warning is recorded into bodyExtractionWarnings but compile.ts prints it nowhere and :437--json warnings carries rule advisories only. This contradicts the extractor header extract-hook-body.ts:14-18 ("makes the build fail … no silent fallback"). Docs hook-bodies.mdx:256 agree with the code, so the header is the outlier. Fix: surface the warning on the default path (at minimum in --json), or correct the header to describe warn-and-bundle.

Clauses that pass

Capability inference (.find→api.read, .update→api.write, const api=ctx.api alias caught), crypto.hash infers nothing (#4391 regression), free-identifier bundle fallback (#1876), all-body-only skip + .mjs cleanup.

QA-source: #10663 · cli.hook-body-extraction-gates · clauses 3, 0, 6

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions