
















11import { describe, expect, it } from "vitest";
22import {
33createTransitiveManifestRiskReport,
4+fetchNpmManifest,
5+readBoundedNpmRegistryText,
46renderTransitiveManifestRiskMarkdownReport,
57} from "../../scripts/transitive-manifest-risk-report.mjs";
68@@ -174,4 +176,108 @@ describe("transitive-manifest-risk-report", () => {
174176expect(markdown).not.toContain("## Notable Findings");
175177expect(markdown).not.toContain("## Additional Sample Findings");
176178});
179+180+it("fetches full npm packuments for the requested manifest version", async () => {
181+const fetchCalls: Array<{ url: string; accept: string | null }> = [];
182+const manifest = await fetchNpmManifest({
183+packageName: "@scope/package",
184+version: "1.0.0",
185+registryBaseUrl: "https://registry.example.test",
186+fetchImpl: async (url, init) => {
187+fetchCalls.push({
188+url: String(url),
189+accept: new Headers(init?.headers).get("accept"),
190+});
191+return new Response(
192+JSON.stringify({
193+time: {
194+"1.0.0": "2026-05-12T00:00:00.000Z",
195+},
196+versions: {
197+"1.0.0": {
198+dependencies: {
199+exact: "1.2.3",
200+},
201+scripts: {
202+install: "node install.js",
203+},
204+},
205+},
206+}),
207+{
208+status: 200,
209+},
210+);
211+},
212+});
213+214+expect(fetchCalls).toEqual([
215+{
216+url: "https://registry.example.test/@scope%2fpackage",
217+accept: "application/json",
218+},
219+]);
220+expect(manifest).toEqual({
221+publishedAt: "2026-05-12T00:00:00.000Z",
222+manifest: {
223+dependencies: {
224+exact: "1.2.3",
225+},
226+scripts: {
227+install: "node install.js",
228+},
229+},
230+});
231+});
232+233+it("rejects npm registry bodies that exceed the content-length cap", async () => {
234+let canceled = false;
235+const response = new Response(
236+new ReadableStream({
237+cancel() {
238+canceled = true;
239+},
240+}),
241+{
242+headers: {
243+"content-length": "12",
244+},
245+},
246+);
247+248+await expect(readBoundedNpmRegistryText(response, 8)).rejects.toThrow(
249+"npm registry response exceeded 8 bytes (content-length 12)",
250+);
251+expect(canceled).toBe(true);
252+});
253+254+it("rejects npm registry bodies that exceed the content-length cap without a body", async () => {
255+const response = new Response(null, {
256+headers: {
257+"content-length": "12",
258+},
259+});
260+261+await expect(readBoundedNpmRegistryText(response, 8)).rejects.toThrow(
262+"npm registry response exceeded 8 bytes (content-length 12)",
263+);
264+});
265+266+it("rejects npm registry bodies that grow past the stream cap", async () => {
267+const encoder = new TextEncoder();
268+const response = new Response(
269+new ReadableStream({
270+start(controller) {
271+controller.enqueue(encoder.encode("1234"));
272+controller.enqueue(encoder.encode("5678"));
273+controller.enqueue(encoder.encode("9"));
274+controller.close();
275+},
276+}),
277+);
278+279+await expect(readBoundedNpmRegistryText(response, 8)).rejects.toThrow(
280+"npm registry response exceeded 8 bytes while reading response body",
281+);
282+});
177283});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。