Files
jhonny-editor/bm/premiere-pro-mcp-main/tests/http-admission.test.ts
T
João Henrique b541f502ba feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto
- Configurado MCP server para Premiere Pro
- Adicionado documentação e skills
- Configurado Gitignore para o projeto
2026-09-08 09:59:31 -04:00

223 lines
10 KiB
TypeScript
Executable File

import { EventEmitter } from "node:events";
import { describe, expect, it, vi } from "vitest";
import {
HttpAdmissionController,
RequestBodyTooLargeError,
exceedsRequestBodyLimit,
getRequestPathname,
isAuthorizedBearer,
isSupportedMcpMethod,
rateLimitIdentity,
readBoundedRequestBody,
readHttpAdmissionSettings,
readHttpAuthConfiguration,
requestContentLength,
} from "../src/http-admission.js";
describe("HTTP admission settings", () => {
it("uses bounded secure defaults and rejects invalid limits", () => {
expect(readHttpAdmissionSettings({})).toMatchObject({
maxRequestBytes: 1_048_576,
maxConcurrentRequests: 8,
maxConcurrentStreams: 32,
rateLimitPerMinute: 120,
rateLimitBurst: 30,
});
expect(() => readHttpAdmissionSettings({ MCP_MAX_REQUEST_BYTES: "unlimited" })).toThrow("MCP_MAX_REQUEST_BYTES");
expect(() => readHttpAdmissionSettings({ MCP_RATE_LIMIT_PER_MINUTE: "10", MCP_RATE_LIMIT_BURST: "11" })).toThrow("MCP_RATE_LIMIT_BURST");
});
it("never permits unauthenticated HTTP in production", () => {
expect(readHttpAuthConfiguration({ MCP_AUTH_TOKEN: "secret", NODE_ENV: "production" })).toEqual({
mode: "shared-token", authToken: "secret", allowUnauthenticated: false,
});
expect(readHttpAuthConfiguration({ ALLOW_UNAUTHENTICATED: "1", NODE_ENV: "test" })).toEqual({
mode: "unauthenticated", allowUnauthenticated: true,
});
expect(() => readHttpAuthConfiguration({ ALLOW_UNAUTHENTICATED: "1", NODE_ENV: "production" })).toThrow("MCP_AUTH_TOKEN");
});
it("requires complete HTTPS OAuth configuration and rejects ambiguous auth modes", () => {
const oauth = readHttpAuthConfiguration({
NODE_ENV: "production",
MCP_OAUTH_ISSUER: "https://identity.example.com",
MCP_OAUTH_AUDIENCE: "https://premiere.example.com/mcp",
MCP_OAUTH_JWKS_URI: "https://identity.example.com/.well-known/jwks.json",
MCP_PUBLIC_URL: "https://premiere.example.com",
MCP_OAUTH_REQUIRED_SCOPES: "premiere:mcp premiere:read",
MCP_OAUTH_ALLOWED_SUBJECTS: "user-1,user-2",
});
expect(oauth).toEqual({
mode: "oauth",
allowUnauthenticated: false,
oauth: {
issuer: "https://identity.example.com",
audience: "https://premiere.example.com/mcp",
jwksUri: "https://identity.example.com/.well-known/jwks.json",
publicUrl: "https://premiere.example.com",
requiredScopes: ["premiere:mcp", "premiere:read"],
allowedSubjects: ["user-1", "user-2"],
},
});
expect(() => readHttpAuthConfiguration({
NODE_ENV: "production", MCP_OAUTH_ISSUER: "https://identity.example.com",
})).toThrow("all required");
expect(() => readHttpAuthConfiguration({
NODE_ENV: "production",
MCP_OAUTH_ISSUER: "http://identity.example.com",
MCP_OAUTH_AUDIENCE: "https://premiere.example.com/mcp",
MCP_OAUTH_JWKS_URI: "https://identity.example.com/jwks.json",
MCP_PUBLIC_URL: "https://premiere.example.com",
MCP_OAUTH_ALLOWED_SUBJECTS: "user-1",
})).toThrow("HTTPS");
expect(() => readHttpAuthConfiguration({
NODE_ENV: "production",
MCP_AUTH_TOKEN: "legacy",
MCP_OAUTH_ISSUER: "https://identity.example.com",
})).toThrow("either MCP_AUTH_TOKEN or MCP_OAUTH_ISSUER");
expect(() => readHttpAuthConfiguration({
NODE_ENV: "production",
MCP_AUTH_TOKEN: "legacy",
MCP_OAUTH_REQUIRED_SCOPES: "premiere:mcp",
})).toThrow("either MCP_AUTH_TOKEN or MCP_OAUTH_ISSUER");
expect(() => readHttpAuthConfiguration({
NODE_ENV: "production",
MCP_OAUTH_ISSUER: "https://identity.example.com",
MCP_OAUTH_AUDIENCE: "https://other.example.com/mcp",
MCP_OAUTH_JWKS_URI: "https://identity.example.com/jwks.json",
MCP_PUBLIC_URL: "https://premiere.example.com",
MCP_OAUTH_ALLOWED_SUBJECTS: "user-1",
})).toThrow("exactly equal");
});
});
describe("HTTP request classification", () => {
it("accepts only the exact MCP pathname and supported methods", () => {
expect(getRequestPathname("/mcp?client=desktop")).toBe("/mcp");
expect(getRequestPathname("/mcp-typo")).not.toBe("/mcp");
expect(getRequestPathname("/mcp%2Fprivate")).not.toBe("/mcp");
expect(getRequestPathname(undefined)).toBeUndefined();
expect(getRequestPathname("http://[")).toBeUndefined();
expect(isSupportedMcpMethod("POST")).toBe(true);
expect(isSupportedMcpMethod("PUT")).toBe(false);
expect(isSupportedMcpMethod(undefined)).toBe(false);
});
it("rejects invalid or over-limit declared body sizes before parsing", () => {
expect(exceedsRequestBodyLimit({ headers: { "content-length": "1024" } } as never, 1024)).toBe(false);
expect(exceedsRequestBodyLimit({ headers: { "content-length": "1025" } } as never, 1024)).toBe(true);
expect(exceedsRequestBodyLimit({ headers: { "content-length": "unknown" } } as never, 1024)).toBe(true);
expect(requestContentLength({ headers: {} } as never)).toBeUndefined();
expect(requestContentLength({ headers: { "content-length": ["1024", "2048"] } } as never)).toBe(1024);
expect(Number.isNaN(requestContentLength({ headers: { "content-length": "9007199254740992" } } as never))).toBe(true);
});
it("bounds chunked bodies before transport parsing", async () => {
const request = Object.assign(new EventEmitter(), {
resume: vi.fn(),
});
const body = readBoundedRequestBody(request as never, 4);
request.emit("data", Buffer.from("four"));
request.emit("data", Buffer.from("!"));
await expect(body).rejects.toBeInstanceOf(RequestBodyTooLargeError);
expect(request.resume).toHaveBeenCalledOnce();
const complete = Object.assign(new EventEmitter(), { resume: vi.fn() });
const completeBody = readBoundedRequestBody(complete as never, 4);
complete.emit("data", Buffer.from("ok"));
complete.emit("data", "!");
complete.emit("end");
await expect(completeBody).resolves.toEqual(Buffer.from("ok!"));
});
it("compares bearer credentials without treating malformed headers as authorized", () => {
const request = (authorization?: string) => ({ headers: { authorization } } as never);
expect(isAuthorizedBearer(request("Bearer a-strong-token"), "a-strong-token")).toBe(true);
expect(isAuthorizedBearer(request("Bearer wrong"), "a-strong-token")).toBe(false);
expect(isAuthorizedBearer(request("Basic a-strong-token"), "a-strong-token")).toBe(false);
expect(isAuthorizedBearer(request(), "a-strong-token")).toBe(false);
expect(isAuthorizedBearer({ headers: { authorization: ["Bearer a-strong-token"] } } as never, "a-strong-token")).toBe(true);
expect(isAuthorizedBearer(request(), undefined)).toBe(true);
});
it("does not trust forwarded addresses unless configured", () => {
const request = {
headers: { "x-forwarded-for": "198.51.100.4, 10.0.0.1" },
socket: { remoteAddress: "10.0.0.1" },
} as never;
expect(rateLimitIdentity(request, false)).not.toBe(rateLimitIdentity(request, true));
expect(rateLimitIdentity({ headers: { "x-forwarded-for": ["203.0.113.8"] }, socket: { remoteAddress: "10.0.0.1" } } as never, true)).toMatch(/^ip:/);
expect(rateLimitIdentity({ headers: {}, socket: { remoteAddress: "" } } as never, false)).toMatch(/^ip:/);
expect(rateLimitIdentity({ headers: {}, socket: {} } as never, true)).toMatch(/^ip:/);
});
});
describe("HTTP admission controller", () => {
it("bounds concurrent requests and makes release idempotent", () => {
const controller = new HttpAdmissionController({
maxConcurrentRequests: 1, maxConcurrentStreams: 2, rateLimitPerMinute: 100, rateLimitBurst: 10, maxRateLimitKeys: 16,
});
const first = controller.acquire("credential:a");
expect(first.accepted).toBe(true);
const second = controller.acquire("credential:b");
expect(second).toMatchObject({ accepted: false, reason: "at_capacity", statusCode: 503 });
if (first.accepted) {
first.release();
first.release();
}
expect(controller.metrics().activeRequests).toBe(0);
expect(controller.acquire("credential:b").accepted).toBe(true);
});
it("enforces a bounded token bucket with Retry-After", () => {
let now = 0;
const controller = new HttpAdmissionController({
maxConcurrentRequests: 5, maxConcurrentStreams: 5, rateLimitPerMinute: 60, rateLimitBurst: 2, maxRateLimitKeys: 16,
}, () => now);
const first = controller.acquire("credential:a");
const second = controller.acquire("credential:a");
if (first.accepted) first.release();
if (second.accepted) second.release();
expect(controller.acquire("credential:a")).toMatchObject({ accepted: false, statusCode: 429, retryAfterSeconds: 1 });
now = 1_000;
expect(controller.acquire("credential:a").accepted).toBe(true);
});
it("bounds tracked identities and prunes stale buckets", () => {
let now = 0;
const controller = new HttpAdmissionController({
maxConcurrentRequests: 2, maxConcurrentStreams: 2, rateLimitPerMinute: 60, rateLimitBurst: 1, maxRateLimitKeys: 1,
}, () => now);
const first = controller.acquire("credential:a");
if (first.accepted) first.release();
expect(controller.acquire("credential:b")).toMatchObject({ accepted: false, reason: "rate_limited" });
now = 120_001;
const second = controller.acquire("credential:b");
expect(second.accepted).toBe(true);
expect(controller.metrics().trackedRateLimitKeys).toBe(1);
if (second.accepted) second.release();
});
it("reserves SSE capacity without consuming operation capacity", () => {
const controller = new HttpAdmissionController({
maxConcurrentRequests: 1, maxConcurrentStreams: 2, rateLimitPerMinute: 100, rateLimitBurst: 10, maxRateLimitKeys: 16,
});
const operation = controller.acquire("credential:a", "operation");
const firstStream = controller.acquire("credential:a", "stream");
const secondStream = controller.acquire("credential:b", "stream");
expect(operation.accepted).toBe(true);
expect(firstStream.accepted).toBe(true);
expect(secondStream.accepted).toBe(true);
expect(controller.acquire("credential:b", "operation")).toMatchObject({ accepted: false, reason: "at_capacity" });
expect(controller.acquire("credential:c", "stream")).toMatchObject({ accepted: false, reason: "at_capacity" });
expect(controller.metrics()).toMatchObject({
activeRequests: 3,
activeOperationRequests: 1,
activeStreamRequests: 2,
});
if (operation.accepted) operation.release();
if (firstStream.accepted) firstStream.release();
if (secondStream.accepted) secondStream.release();
});
});