Implement pagination with link headers for Adoptium based apis (#1014)

* Use Link headers for Adoptium pagination

* Fix nullable pagination URL types and rebuild dist

* Add 1000-page safeguard for JetBrains pagination

* Adjust plan for pagination safeguard scope

* Move pagination safeguard to non-JetBrains installers

* Add 1000-page safeguard to Adopt Temurin and Semeru pagination

* Fix Prettier formatting in adopt, semeru, and temurin installer files

* Fix CI audit failure by updating vulnerable transitive deps

* Address PR review: RFC-compliant Link parsing, SSRF validation, centralized constant

- Make getNextPageUrlFromLinkHeader RFC 8288 compliant by splitting
  link-values and checking for rel=next anywhere in the parameters,
  not just as the first parameter after the semicolon.
- Add validatePaginationUrl utility to reject pagination URLs that
  point to unexpected origins (SSRF mitigation).
- Centralize MAX_PAGINATION_PAGES in util.ts instead of duplicating
  across Adopt, Semeru, and Temurin installers.
- Add tests for rel not being the first parameter, and for URL
  origin validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address code review feedback on pagination implementation

- Tighten rel regex with word boundary to prevent false positives
  (e.g., rel="nextsomething" no longer matches).
- Use parsed.origin comparison in validatePaginationUrl to correctly
  handle explicit default ports (e.g., :443 for HTTPS).
- Fix pagination safeguard tests to use same-origin URLs so they
  actually exercise the 1000-page limit instead of being rejected
  by origin validation on the first request.
- Add test for rel="nextsomething" not matching.
- Add test for explicit default port acceptance.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix prettier formatting in util.test.ts

* Rebuild dist/ to fix check-dist CI failure

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
John
2026-06-12 11:50:16 +01:00
committed by GitHub
parent ad9d6a6320
commit 43120bc3c3
11 changed files with 496 additions and 111 deletions

43
dist/cleanup/index.js vendored
View File

@@ -52134,7 +52134,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.renameWinArchive = exports.getGitHubHttpHeaders = exports.convertVersionToSemver = exports.getVersionFromFileContent = exports.isCacheFeatureAvailable = exports.isGhes = exports.isJobStatusSuccess = exports.getToolcachePath = exports.isVersionSatisfies = exports.getDownloadArchiveExtension = exports.extractJdkFile = exports.getVersionFromToolcachePath = exports.getBooleanInput = exports.getTempDir = void 0;
exports.renameWinArchive = exports.validatePaginationUrl = exports.getNextPageUrlFromLinkHeader = exports.MAX_PAGINATION_PAGES = exports.getGitHubHttpHeaders = exports.convertVersionToSemver = exports.getVersionFromFileContent = exports.isCacheFeatureAvailable = exports.isGhes = exports.isJobStatusSuccess = exports.getToolcachePath = exports.isVersionSatisfies = exports.getDownloadArchiveExtension = exports.extractJdkFile = exports.getVersionFromToolcachePath = exports.getBooleanInput = exports.getTempDir = void 0;
const os_1 = __importDefault(__nccwpck_require__(22037));
const path_1 = __importDefault(__nccwpck_require__(71017));
const fs = __importStar(__nccwpck_require__(57147));
@@ -52301,6 +52301,47 @@ function getGitHubHttpHeaders() {
return headers;
}
exports.getGitHubHttpHeaders = getGitHubHttpHeaders;
exports.MAX_PAGINATION_PAGES = 1000;
function getNextPageUrlFromLinkHeader(headers) {
var _a;
if (!headers) {
return null;
}
const linkHeader = (_a = headers.link) !== null && _a !== void 0 ? _a : headers.Link;
if (!linkHeader) {
return null;
}
const normalizedLinkHeader = Array.isArray(linkHeader)
? linkHeader.join(',')
: linkHeader;
// Split into individual link-values and find the one with rel="next"
// RFC 8288 allows rel to appear anywhere among the parameters
const linkValues = normalizedLinkHeader.split(/,(?=\s*<)/);
for (const linkValue of linkValues) {
const urlMatch = linkValue.match(/<([^>]+)>/);
if (!urlMatch)
continue;
const params = linkValue.slice(urlMatch[0].length);
// Use word boundary to match "next" as a standalone relation type
// RFC 8288 allows space-separated relation types like rel="next prev"
if (/;\s*rel="?[^"]*\bnext\b/i.test(params)) {
return urlMatch[1];
}
}
return null;
}
exports.getNextPageUrlFromLinkHeader = getNextPageUrlFromLinkHeader;
function validatePaginationUrl(url, allowedOrigin) {
try {
const parsed = new URL(url);
const allowed = new URL(allowedOrigin);
return parsed.origin === allowed.origin;
}
catch (_a) {
return false;
}
}
exports.validatePaginationUrl = validatePaginationUrl;
// Rename archive to add extension because after downloading
// archive does not contain extension type and it leads to some issues
// on Windows runners without PowerShell Core.