From 1a2805ba56539d35d86d452c71555ae0673b9864 Mon Sep 17 00:00:00 2001 From: Reinier Criel Date: Thu, 2 Apr 2026 13:00:01 -0700 Subject: [PATCH] Adapt per review --- .../interceptors/pip/modifyPipInfo.js | 70 +++++++++++++------ .../interceptors/pip/modifyPipInfo.spec.js | 26 +++++++ 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/packages/safe-chain/src/registryProxy/interceptors/pip/modifyPipInfo.js b/packages/safe-chain/src/registryProxy/interceptors/pip/modifyPipInfo.js index d3d10fe..9ef4328 100644 --- a/packages/safe-chain/src/registryProxy/interceptors/pip/modifyPipInfo.js +++ b/packages/safe-chain/src/registryProxy/interceptors/pip/modifyPipInfo.js @@ -6,6 +6,11 @@ export { parsePipMetadataUrl, isPipPackageInfoUrl } from "./parsePipPackageUrl.j import { getPipMetadataContentType, logSuppressedVersion } from "./pipMetadataResponseUtils.js"; import { modifyPipJsonResponse } from "./modifyPipJsonResponse.js"; +// Match simple-index anchor tags and capture their href so we can suppress +// individual distribution links from PyPI HTML metadata responses. +const HTML_ANCHOR_HREF_RE = + /]*href\s*=\s*(["'])([^"']+)\1[^>]*>[\s\S]*?<\/a>/gi; + /** * @param {Buffer} body * @param {NodeJS.Dict | undefined} headers @@ -80,30 +85,15 @@ function modifyHtmlSimpleResponse( ) { const html = body.toString("utf8"); let modified = false; - - const updatedHtml = html.replace( - /]*href\s*=\s*(["'])([^"']+)\1[^>]*>[\s\S]*?<\/a>/gi, - (anchor, _quote, href) => { - const resolvedHref = new URL(href, metadataUrl).toString(); - const { packageName: hrefPackageName, version } = parsePipPackageFromUrl( - resolvedHref, - new URL(resolvedHref).host - ); - - if ( - hrefPackageName && - normalizePipPackageName(hrefPackageName) === normalizePipPackageName(packageName) && - version && - isNewlyReleasedPackage(packageName, version) - ) { - modified = true; - logSuppressedVersion(packageName, version); - return ""; - } - - return anchor; + const rewriteHtmlAnchor = createHtmlAnchorRewriter( + metadataUrl, + isNewlyReleasedPackage, + packageName, + () => { + modified = true; } ); + const updatedHtml = html.replace(HTML_ANCHOR_HREF_RE, rewriteHtmlAnchor); if (!modified) return body; const modifiedBuffer = Buffer.from(updatedHtml); @@ -111,6 +101,42 @@ function modifyHtmlSimpleResponse( return modifiedBuffer; } +/** + * @param {string} metadataUrl + * @param {(packageName: string | undefined, version: string | undefined) => boolean} isNewlyReleasedPackage + * @param {string} packageName + * @param {() => void} onModified + * @returns {(anchor: string, quote: string, href: string) => string} + */ +function createHtmlAnchorRewriter( + metadataUrl, + isNewlyReleasedPackage, + packageName, + onModified +) { + return (anchor, _quote, href) => { + const resolvedHref = new URL(href, metadataUrl).toString(); + const { packageName: hrefPackageName, version } = parsePipPackageFromUrl( + resolvedHref, + new URL(resolvedHref).host + ); + + if ( + hrefPackageName && + normalizePipPackageName(hrefPackageName) === + normalizePipPackageName(packageName) && + version && + isNewlyReleasedPackage(packageName, version) + ) { + onModified(); + logSuppressedVersion(packageName, version); + return ""; + } + + return anchor; + }; +} + /** * @param {Buffer} body * @param {NodeJS.Dict | undefined} headers diff --git a/packages/safe-chain/src/registryProxy/interceptors/pip/modifyPipInfo.spec.js b/packages/safe-chain/src/registryProxy/interceptors/pip/modifyPipInfo.spec.js index 46a872f..900941d 100644 --- a/packages/safe-chain/src/registryProxy/interceptors/pip/modifyPipInfo.spec.js +++ b/packages/safe-chain/src/registryProxy/interceptors/pip/modifyPipInfo.spec.js @@ -134,6 +134,32 @@ describe("modifyPipInfo", async () => { assert.ok(modified.includes("foo_bar-1.0.0.tar.gz")); }); + it("matches anchor href regex with single quotes and extra attributes", () => { + const headers = { "content-type": "application/vnd.pypi.simple.v1+html" }; + + const body = Buffer.from(` + + foo_bar-2.0.0.tar.gz + + foo_bar-1.0.0.tar.gz + `); + + const modified = modifyPipInfoResponse( + body, + headers, + "https://pypi.org/simple/foo-bar/", + (_packageName, version) => version === "2.0.0", + "foo-bar" + ).toString("utf8"); + + assert.ok(!modified.includes("foo_bar-2.0.0.tar.gz")); + assert.ok(modified.includes("foo_bar-1.0.0.tar.gz")); + }); + it("removes too-young files from simple JSON metadata", () => { const headers = { "content-type": "application/vnd.pypi.simple.v1+json",