History

Add real protocol testing fixtures

Rhys Sullivan committed 6 months ago

Commit ac6b02a1 parent 64c2eb725 files · +702 −197Browse files

Showing the changes to scripts (2 of 25 files). Show all

Unified · Split

2 files
  1. scripts/oxlint-plugin-executor.js +2 −0
  2. scripts/oxlint-plugin-executor/rules/no-raw-fetch.js +76 −0
scripts/oxlint-plugin-executor.js+2−0
@@ -12,6 +12,7 @@ import noManualTagCheck from "./oxlint-plugin-executor/rules/no-manual-tag-check · 11 unmodified lines
1212 import noPromiseCatch from "./oxlint-plugin-executor/rules/no-promise-catch.js";
1313 import noPromiseClientSurface from "./oxlint-plugin-executor/rules/no-promise-client-surface.js";
1414 import noPromiseReject from "./oxlint-plugin-executor/rules/no-promise-reject.js";
15+import noRawFetch from "./oxlint-plugin-executor/rules/no-raw-fetch.js";
1516 import noRawErrorThrow from "./oxlint-plugin-executor/rules/no-raw-error-throw.js";
1617 import noRedundantPrimitiveCast from "./oxlint-plugin-executor/rules/no-redundant-primitive-cast.js";
1718 import noRedundantErrorFactory from "./oxlint-plugin-executor/rules/no-redundant-error-factory.js";
@@ -48,6 +49,7 @@ export default { · 30 unmodified lines
4849 "no-promise-catch": noPromiseCatch,
4950 "no-promise-client-surface": noPromiseClientSurface,
5051 "no-promise-reject": noPromiseReject,
52+ "no-raw-fetch": noRawFetch,
5153 "no-raw-error-throw": noRawErrorThrow,
5254 "no-redundant-primitive-cast": noRedundantPrimitiveCast,
5355 "no-redundant-error-factory": noRedundantErrorFactory,
scripts/oxlint-plugin-executor/rules/no-raw-fetch.js+76−0
@@ -0,0 +1,76 @@
1+import {
2+ getPropertyName,
3+ isDeclarationFile,
4+ isIdentifier,
5+ toRepoRelative,
6+ unwrapExpression,
7+} from "../utils.js";
8+
9+const message =
10+ "Do not call raw fetch in core/plugin code. Route HTTP through Effect HttpClient or an explicit package-local boundary. Skill: wrdn-effect-raw-fetch-boundary.";
11+
12+const checkedPrefixes = [
13+ "packages/core/sdk/src/",
14+ "packages/plugins/graphql/src/",
15+ "packages/plugins/mcp/src/",
16+ "packages/plugins/openapi/src/",
17+];
18+
19+const temporaryAllowedFiles = new Set([
20+ "packages/core/sdk/src/oauth-discovery.ts",
21+ "packages/core/sdk/src/oauth-discovery.test.ts",
22+ "packages/core/sdk/src/oauth-helpers.test.ts",
23+ "packages/core/sdk/src/oauth-service.ts",
24+ "packages/plugins/mcp/src/sdk/probe-shape.ts",
25+ "packages/plugins/openapi/src/sdk/client-credentials-oauth.test.ts",
26+ "packages/plugins/openapi/src/sdk/multi-scope-oauth.test.ts",
27+ "packages/plugins/openapi/src/sdk/oauth-refresh.test.ts",
28+]);
29+
30+const shouldCheck = (filename) => {
31+ const normalized = toRepoRelative(filename);
32+ if (isDeclarationFile(filename)) return false;
33+ if (temporaryAllowedFiles.has(normalized)) return false;
34+ return checkedPrefixes.some((prefix) => normalized.startsWith(prefix));
35+};
36+
37+const isGlobalFetchMember = (node) => {
38+ const expression = unwrapExpression(node);
39+ if (expression?.type !== "MemberExpression") return false;
40+ const object = unwrapExpression(expression.object);
41+ const property = getPropertyName(expression.property);
42+ return (
43+ property === "fetch" &&
44+ (isIdentifier(object, "globalThis") ||
45+ isIdentifier(object, "window") ||
46+ isIdentifier(object, "self"))
47+ );
48+};
49+
50+const isBareFetchCall = (node) => isIdentifier(unwrapExpression(node), "fetch");
51+
52+export default {
53+ meta: {
54+ type: "problem",
55+ docs: {
56+ description: "Disallow raw fetch outside approved Effect HTTP boundaries.",
57+ },
58+ },
59+ create(context) {
60+ if (!shouldCheck(context.filename)) return {};
61+
62+ return {
63+ CallExpression(node) {
64+ if (isBareFetchCall(node.callee) || isGlobalFetchMember(node.callee)) {
65+ context.report({ node: node.callee, message });
66+ }
67+ },
68+ MemberExpression(node) {
69+ if (node.parent?.type === "CallExpression" && node.parent.callee === node) return;
70+ if (isGlobalFetchMember(node)) {
71+ context.report({ node, message });
72+ }
73+ },
74+ };
75+ },
76+};