test: guard raw HTTP2 APNs connections

This commit is contained in:
jesse-merhi
2026-05-04 02:30:39 +10:00
committed by clawsweeper
parent 543bbcba9d
commit 81d7696673
3 changed files with 85 additions and 0 deletions

View File

@@ -1426,6 +1426,7 @@
"lint:tmp:dynamic-import-warts": "node scripts/check-dynamic-import-warts.mjs",
"lint:tmp:no-random-messaging": "node scripts/check-no-random-messaging-tmp.mjs",
"lint:tmp:no-raw-channel-fetch": "node scripts/check-no-raw-channel-fetch.mjs",
"lint:tmp:no-raw-http2-connect": "node scripts/check-no-raw-http2-connect.mjs",
"lint:tmp:tsgo-core-boundary": "node scripts/check-tsgo-core-boundary.mjs",
"lint:ui:no-raw-window-open": "node scripts/check-no-raw-window-open.mjs",
"lint:web-fetch-provider-boundaries": "node scripts/check-web-fetch-provider-boundaries.mjs",

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env node
import path from "node:path";
import ts from "typescript";
import { runCallsiteGuard } from "./lib/callsite-guard.mjs";
import {
collectCallExpressionLines,
runAsScript,
unwrapExpression,
} from "./lib/ts-guard-utils.mjs";
const sourceRoots = ["src", "extensions"];
const allowedRawHttp2ConnectCallsites = new Set([
"src/infra/push-apns-http2.ts:39",
"src/infra/push-apns-http2.ts:55",
]);
function isHttp2ConnectCall(expression) {
const callee = unwrapExpression(expression);
if (!ts.isPropertyAccessExpression(callee) || callee.name.text !== "connect") {
return false;
}
const receiver = unwrapExpression(callee.expression);
return ts.isIdentifier(receiver) && receiver.text === "http2";
}
export function findRawHttp2ConnectCallLines(content, fileName = "source.ts") {
const sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true);
return collectCallExpressionLines(ts, sourceFile, (node) =>
isHttp2ConnectCall(node.expression) ? node.expression : null,
);
}
export async function main() {
await runCallsiteGuard({
importMetaUrl: import.meta.url,
sourceRoots,
extraTestSuffixes: [".browser.test.ts", ".node.test.ts"],
findCallLines: findRawHttp2ConnectCallLines,
allowCallsite: (callsite) => allowedRawHttp2ConnectCallsites.has(callsite),
skipRelativePath: (relPath) =>
relPath === path.posix.join("src", "infra", "push-apns-http2.test.ts"),
header: "Found raw http2.connect usage outside APNs proxy wrapper:",
footer:
"Use connectApnsHttp2Session() from src/infra/push-apns-http2.ts so APNs HTTP/2 honors managed proxy policy.",
});
}
runAsScript(import.meta.url, main);

View File

@@ -0,0 +1,35 @@
import { describe, expect, it } from "vitest";
import { findRawHttp2ConnectCallLines } from "../../scripts/check-no-raw-http2-connect.mjs";
describe("check-no-raw-http2-connect", () => {
it("finds direct http2.connect calls", () => {
const source = `
import http2 from "node:http2";
export function connect() {
return http2.connect("https://api.push.apple.com");
}
`;
expect(findRawHttp2ConnectCallLines(source)).toEqual([4]);
});
it("finds parenthesized or asserted http2 references", () => {
const source = `
import http2 from "node:http2";
export function connect() {
return (http2 as typeof import("node:http2")).connect("https://api.push.apple.com");
}
`;
expect(findRawHttp2ConnectCallLines(source)).toEqual([4]);
});
it("ignores mentions in strings and comments", () => {
const source = `
// http2.connect("https://api.push.apple.com")
const text = "http2.connect('https://api.push.apple.com')";
`;
expect(findRawHttp2ConnectCallLines(source)).toEqual([]);
});
});