2023-03-21 11:32:38 +02:00
import { HttpClient } from '@actions/http-client' ;
import { JavaInstallerOptions } from '../../src/distributions/base-models' ;
import { SemeruDistribution } from '../../src/distributions/semeru/installer' ;
import manifestData from '../data/semeru.json' ;
2026-04-13 23:14:45 +05:30
import * as core from '@actions/core' ;
2023-03-21 11:32:38 +02:00
describe ( 'getAvailableVersions' , ( ) = > {
let spyHttpClient : jest.SpyInstance ;
2026-04-13 23:14:45 +05:30
let spyCoreError : jest.SpyInstance ;
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>
2026-06-12 11:50:16 +01:00
let spyCoreWarning : jest.SpyInstance ;
2023-03-21 11:32:38 +02:00
beforeEach ( ( ) = > {
spyHttpClient = jest . spyOn ( HttpClient . prototype , 'getJson' ) ;
spyHttpClient . mockReturnValue ( {
statusCode : 200 ,
headers : { } ,
result : [ ]
} ) ;
2026-04-13 23:14:45 +05:30
// Mock core.error to suppress error logs
spyCoreError = jest . spyOn ( core , 'error' ) ;
spyCoreError . mockImplementation ( ( ) = > { } ) ;
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>
2026-06-12 11:50:16 +01:00
spyCoreWarning = jest . spyOn ( core , 'warning' ) ;
spyCoreWarning . mockImplementation ( ( ) = > { } ) ;
2023-03-21 11:32:38 +02:00
} ) ;
afterEach ( ( ) = > {
jest . resetAllMocks ( ) ;
jest . clearAllMocks ( ) ;
jest . restoreAllMocks ( ) ;
} ) ;
it . each ( [
[
{
version : '16' ,
architecture : 'x64' ,
packageType : 'jdk' ,
checkLatest : false
} ,
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
] ,
[
{
version : '16' ,
architecture : 'x86' ,
packageType : 'jdk' ,
checkLatest : false
} ,
'os=mac&architecture=x86&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
] ,
[
{
version : '16' ,
architecture : 'x64' ,
packageType : 'jre' ,
checkLatest : false
} ,
'os=mac&architecture=x64&image_type=jre&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
] ,
[
{
version : '16' ,
architecture : 'x64' ,
packageType : 'jdk' ,
checkLatest : false
} ,
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
]
] ) (
'build correct url for %s' ,
async ( installerOptions : JavaInstallerOptions , expectedParameters ) = > {
const distribution = new SemeruDistribution ( installerOptions ) ;
const baseUrl =
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D' ;
const expectedUrl = ` ${ baseUrl } ?project=jdk&vendor=ibm&heap_size=normal&sort_method=DEFAULT&sort_order=DESC& ${ expectedParameters } ` ;
distribution [ 'getPlatformOption' ] = ( ) = > 'mac' ;
await distribution [ 'getAvailableVersions' ] ( ) ;
expect ( spyHttpClient . mock . calls ) . toHaveLength ( 1 ) ;
expect ( spyHttpClient . mock . calls [ 0 ] [ 0 ] ) . toBe ( expectedUrl ) ;
}
) ;
it ( 'load available versions' , async ( ) = > {
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>
2026-06-12 11:50:16 +01:00
const nextPageUrl =
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20' ;
2023-03-21 11:32:38 +02:00
spyHttpClient = jest . spyOn ( HttpClient . prototype , 'getJson' ) ;
spyHttpClient
. mockReturnValueOnce ( {
statusCode : 200 ,
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>
2026-06-12 11:50:16 +01:00
headers : { link : ` < ${ nextPageUrl } >; rel="next" ` } ,
2023-03-21 11:32:38 +02:00
result : manifestData as any
} )
. mockReturnValueOnce ( {
statusCode : 200 ,
headers : { } ,
result : manifestData as any
} ) ;
const distribution = new SemeruDistribution ( {
version : '8' ,
architecture : 'x64' ,
packageType : 'jdk' ,
checkLatest : false
} ) ;
const availableVersions = await distribution [ 'getAvailableVersions' ] ( ) ;
expect ( availableVersions ) . not . toBeNull ( ) ;
expect ( availableVersions . length ) . toBe ( manifestData . length * 2 ) ;
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>
2026-06-12 11:50:16 +01:00
expect ( spyHttpClient ) . toHaveBeenNthCalledWith ( 2 , nextPageUrl ) ;
} ) ;
it ( 'stops pagination after 1000 pages as a safeguard' , async ( ) = > {
const nextPageUrl =
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=2&page_size=20' ;
spyHttpClient . mockReturnValue ( {
statusCode : 200 ,
headers : { link : ` < ${ nextPageUrl } >; rel="next" ` } ,
result : [ { version_data : { semver : '17.0.1' } , binaries : [ ] } ] as any
} ) ;
const distribution = new SemeruDistribution ( {
version : '8' ,
architecture : 'x64' ,
packageType : 'jdk' ,
checkLatest : false
} ) ;
await distribution [ 'getAvailableVersions' ] ( ) ;
expect ( spyHttpClient ) . toHaveBeenCalledTimes ( 1000 ) ;
expect ( spyCoreWarning ) . toHaveBeenCalledWith (
expect . stringContaining ( 'Reached pagination safeguard limit (1000 pages)' )
) ;
2023-03-21 11:32:38 +02:00
} ) ;
it . each ( [
[ 'jdk' , 'Java_IBM_Semeru_jdk' ] ,
[ 'jre' , 'Java_IBM_Semeru_jre' ]
] ) ( 'find right toolchain folder' , ( packageType : string , expected : string ) = > {
const distribution = new SemeruDistribution ( {
version : '8' ,
architecture : 'x64' ,
packageType : packageType ,
checkLatest : false
} ) ;
// @ts-ignore - because it is protected
expect ( distribution . toolcacheFolderName ) . toBe ( expected ) ;
} ) ;
} ) ;
describe ( 'findPackageForDownload' , ( ) = > {
it . each ( [
[ '8' , '8.0.322+6' ] ,
[ '16' , '16.0.2+7' ] ,
[ '16.0' , '16.0.2+7' ] ,
[ '16.0.2' , '16.0.2+7' ] ,
[ '8.x' , '8.0.322+6' ] ,
[ 'x' , '17.0.2+8' ]
] ) ( 'version is resolved correctly %s -> %s' , async ( input , expected ) = > {
const distribution = new SemeruDistribution ( {
version : '8' ,
architecture : 'x64' ,
packageType : 'jdk' ,
checkLatest : false
} ) ;
distribution [ 'getAvailableVersions' ] = async ( ) = > manifestData as any ;
const resolvedVersion = await distribution [ 'findPackageForDownload' ] ( input ) ;
expect ( resolvedVersion . version ) . toBe ( expected ) ;
} ) ;
it ( 'version is found but binaries list is empty' , async ( ) = > {
const distribution = new SemeruDistribution ( {
version : '9.0.8' ,
architecture : 'x64' ,
packageType : 'jdk' ,
checkLatest : false
} ) ;
distribution [ 'getAvailableVersions' ] = async ( ) = > manifestData as any ;
await expect (
distribution [ 'findPackageForDownload' ] ( '9.0.8' )
2026-04-13 23:14:45 +05:30
) . rejects . toThrow ( /No matching version found for SemVer */ ) ;
2023-03-21 11:32:38 +02:00
} ) ;
it ( 'version is not found' , async ( ) = > {
const distribution = new SemeruDistribution ( {
version : '7.x' ,
architecture : 'x64' ,
packageType : 'jdk' ,
checkLatest : false
} ) ;
distribution [ 'getAvailableVersions' ] = async ( ) = > manifestData as any ;
await expect ( distribution [ 'findPackageForDownload' ] ( '7.x' ) ) . rejects . toThrow (
2026-04-13 23:14:45 +05:30
/No matching version found for SemVer */
2023-03-21 11:32:38 +02:00
) ;
} ) ;
it ( 'version list is empty' , async ( ) = > {
const distribution = new SemeruDistribution ( {
version : '8' ,
architecture : 'x64' ,
packageType : 'jdk' ,
checkLatest : false
} ) ;
distribution [ 'getAvailableVersions' ] = async ( ) = > [ ] ;
await expect ( distribution [ 'findPackageForDownload' ] ( '8' ) ) . rejects . toThrow (
2026-04-13 23:14:45 +05:30
/No matching version found for SemVer */
2023-03-21 11:32:38 +02:00
) ;
} ) ;
it . each ( [ 'x64' , 'x86' , 'ppc64le' , 'ppc64' , 's390x' , 'aarch64' ] ) (
'correct Semeru `%s` architecture resolves' ,
async ( arch : string ) = > {
const distribution = new SemeruDistribution ( {
version : '8' ,
architecture : arch ,
packageType : 'jdk' ,
checkLatest : false
} ) ;
distribution [ 'getAvailableVersions' ] = async ( ) = > manifestData as any ;
const resolvedVersion = await distribution [ 'findPackageForDownload' ] ( '8' ) ;
expect ( resolvedVersion . version ) . not . toBeNull ( ) ;
}
) ;
it . each ( [ 'zos' , 'z/OS' , 'z/os' , 'test0987654321=' , '++=++' , 'myArch' ] ) (
'incorrect Semeru `%s` architecture throws' ,
async ( arch : string ) = > {
const distribution = new SemeruDistribution ( {
version : '8' ,
architecture : arch ,
packageType : 'jdk' ,
checkLatest : false
} ) ;
distribution [ 'getAvailableVersions' ] = async ( ) = > [ ] ;
await expect ( distribution [ 'findPackageForDownload' ] ( '8' ) ) . rejects . toThrow (
2024-08-30 00:18:24 +05:30
` Unsupported architecture for IBM Semeru: ${ arch } for your current OS version, the following are supported: x64, x86, ppc64le, ppc64, s390x, aarch64 `
2023-03-21 11:32:38 +02:00
) ;
}
) ;
it . each ( [ '9-ea' , '17-ea' , '8-ea' , '4-ea' ] ) (
'early access version are illegal for Semeru (%s)' ,
async ( version : string ) = > {
const distribution = new SemeruDistribution ( {
version : version ,
architecture : 'x64' ,
packageType : 'jdk' ,
checkLatest : false
} ) ;
distribution [ 'getAvailableVersions' ] = async ( ) = > manifestData as any ;
await expect (
distribution [ 'findPackageForDownload' ] ( version )
) . rejects . toThrow (
'IBM Semeru does not provide builds for early access versions'
) ;
}
) ;
it . each ( [
'jdk+fx' ,
'jre+fx' ,
'test' ,
'test2' ,
'jdk-fx' ,
'javafx' ,
'jdk-javafx' ,
'ibm' ,
' '
] ) (
'rejects incorrect `%s` Semeru package type' ,
async ( packageType : string ) = > {
const distribution = new SemeruDistribution ( {
version : '8' ,
architecture : 'x64' ,
packageType : packageType ,
checkLatest : false
} ) ;
distribution [ 'getAvailableVersions' ] = async ( ) = > manifestData as any ;
await expect ( distribution [ 'findPackageForDownload' ] ( '8' ) ) . rejects . toThrow (
'IBM Semeru only provide `jdk` and `jre` package types'
) ;
}
) ;
it . each ( [ 'jdk' , 'jre' ] ) (
'accepts correct `%s` Semeru package type' ,
async ( packageType : string ) = > {
const distribution = new SemeruDistribution ( {
version : '8' ,
architecture : 'x64' ,
packageType : packageType ,
checkLatest : false
} ) ;
distribution [ 'getAvailableVersions' ] = async ( ) = > manifestData as any ;
const resolvedVersion = await distribution [ 'findPackageForDownload' ] ( '8' ) ;
await expect ( resolvedVersion . version ) . toMatch ( /8[0-9.]+/ ) ;
}
) ;
it ( 'fails when long release name is used' , async ( ) = > {
expect (
( ) = >
new SemeruDistribution ( {
version : 'jdk-16.0.2+7_openj9-0.27.1' ,
architecture : 'x64' ,
packageType : 'jdk' ,
checkLatest : false
} )
) . toThrow (
"The string 'jdk-16.0.2+7_openj9-0.27.1' is not valid SemVer notation for a Java version. Please check README file for code snippets and more detailed information"
) ;
} ) ;
} ) ;