mirror of
https://github.com/apple/pkl.git
synced 2026-07-01 02:31:45 +02:00
d012285f7d
This implements HTTP redirect following ourselves. The goal is: 1. All I/O is checked against `--allowed-resources` and `--allowed-modules`, including HTTP redirects 2. HTTP rewrite rules can affect redirect following 3. HTTP headers can affect redirect following --------- Co-authored-by: Islon Scherer <islonscherer@gmail.com>
237 lines
8.2 KiB
Kotlin
237 lines
8.2 KiB
Kotlin
/*
|
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package org.pkl.cli
|
|
|
|
import java.nio.file.Path
|
|
import org.assertj.core.api.Assertions.assertThat
|
|
import org.assertj.core.api.Assertions.assertThatCode
|
|
import org.junit.jupiter.api.AfterAll
|
|
import org.junit.jupiter.api.Test
|
|
import org.junit.jupiter.api.io.TempDir
|
|
import org.pkl.commons.cli.CliBaseOptions
|
|
import org.pkl.commons.test.FileTestUtils
|
|
import org.pkl.commons.test.PackageServer
|
|
import org.pkl.core.packages.PackageUri
|
|
|
|
class CliPackageDownloaderTest {
|
|
companion object {
|
|
private val server = PackageServer()
|
|
|
|
@AfterAll
|
|
@JvmStatic
|
|
fun afterAll() {
|
|
server.close()
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `download packages`(@TempDir tempDir: Path) {
|
|
val cmd =
|
|
CliPackageDownloader(
|
|
baseOptions =
|
|
CliBaseOptions(
|
|
moduleCacheDir = tempDir,
|
|
caCertificates = listOf(FileTestUtils.selfSignedCertificatePem),
|
|
testPort = server.port,
|
|
),
|
|
packageUris =
|
|
listOf(
|
|
PackageUri("package://localhost:0/birds@0.5.0"),
|
|
PackageUri("package://localhost:0/fruit@1.0.5"),
|
|
PackageUri("package://localhost:0/fruit@1.1.0"),
|
|
),
|
|
noTransitive = true,
|
|
)
|
|
cmd.run()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip")).exists()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.json")).exists()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/fruit@1.0.5/fruit@1.0.5.zip")).exists()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/fruit@1.0.5/fruit@1.0.5.json")).exists()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/fruit@1.1.0/fruit@1.1.0.zip")).exists()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/fruit@1.1.0/fruit@1.1.0.json")).exists()
|
|
}
|
|
|
|
@Test
|
|
fun `download packages with cache dir set by project`(@TempDir tempDir: Path) {
|
|
tempDir.writeFile(
|
|
"PklProject",
|
|
"""
|
|
amends "pkl:Project"
|
|
|
|
evaluatorSettings {
|
|
moduleCacheDir = ".my-cache"
|
|
}
|
|
"""
|
|
.trimIndent(),
|
|
)
|
|
|
|
val cmd =
|
|
CliPackageDownloader(
|
|
baseOptions =
|
|
CliBaseOptions(
|
|
workingDir = tempDir,
|
|
caCertificates = listOf(FileTestUtils.selfSignedCertificatePem),
|
|
testPort = server.port,
|
|
),
|
|
packageUris = listOf(PackageUri("package://localhost:0/birds@0.5.0")),
|
|
noTransitive = true,
|
|
)
|
|
cmd.run()
|
|
assertThat(tempDir.resolve(".my-cache/package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip"))
|
|
.exists()
|
|
assertThat(tempDir.resolve(".my-cache/package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.json"))
|
|
.exists()
|
|
}
|
|
|
|
@Test
|
|
fun `download package while specifying checksum`(@TempDir tempDir: Path) {
|
|
val cmd =
|
|
CliPackageDownloader(
|
|
baseOptions =
|
|
CliBaseOptions(
|
|
moduleCacheDir = tempDir,
|
|
caCertificates = listOf(FileTestUtils.selfSignedCertificatePem),
|
|
testPort = server.port,
|
|
),
|
|
packageUris =
|
|
listOf(
|
|
PackageUri("package://localhost:0/birds@0.5.0::sha256:${PackageServer.BIRDS_SHA}")
|
|
),
|
|
noTransitive = true,
|
|
)
|
|
cmd.run()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip")).exists()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.json")).exists()
|
|
}
|
|
|
|
@Test
|
|
fun `download package with invalid checksum`(@TempDir tempDir: Path) {
|
|
val cmd =
|
|
CliPackageDownloader(
|
|
baseOptions =
|
|
CliBaseOptions(
|
|
moduleCacheDir = tempDir,
|
|
caCertificates = listOf(FileTestUtils.selfSignedCertificatePem),
|
|
testPort = server.port,
|
|
),
|
|
packageUris =
|
|
listOf(
|
|
PackageUri("package://localhost:0/birds@0.5.0::sha256:intentionallyBogusChecksum")
|
|
),
|
|
noTransitive = true,
|
|
)
|
|
assertThatCode { cmd.run() }
|
|
.hasMessage(
|
|
"""
|
|
Cannot download package `package://localhost:0/birds@0.5.0` because the computed checksum for package metadata does not match the expected checksum.
|
|
|
|
Computed checksum: "${PackageServer.BIRDS_SHA}"
|
|
Expected checksum: "intentionallyBogusChecksum"
|
|
Asset URL: "https://localhost:0/birds@0.5.0"
|
|
"""
|
|
.trimIndent()
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `disabling caching is an error`(@TempDir tempDir: Path) {
|
|
val cmd =
|
|
CliPackageDownloader(
|
|
baseOptions = CliBaseOptions(workingDir = tempDir, noCache = true),
|
|
packageUris = listOf(PackageUri("package://localhost:0/birds@0.5.0")),
|
|
noTransitive = true,
|
|
)
|
|
assertThatCode { cmd.run() }
|
|
.hasMessage("Cannot download packages because no cache directory is specified.")
|
|
}
|
|
|
|
@Test
|
|
fun `download packages with bad checksum`(@TempDir tempDir: Path) {
|
|
val cmd =
|
|
CliPackageDownloader(
|
|
baseOptions =
|
|
CliBaseOptions(
|
|
moduleCacheDir = tempDir,
|
|
caCertificates = listOf(FileTestUtils.selfSignedCertificatePem),
|
|
testPort = server.port,
|
|
),
|
|
packageUris = listOf(PackageUri("package://localhost:0/badChecksum@1.0.0")),
|
|
noTransitive = true,
|
|
)
|
|
assertThatCode { cmd.run() }
|
|
.hasMessageStartingWith(
|
|
"Cannot download package `package://localhost:0/badChecksum@1.0.0` because the computed checksum does not match the expected checksum."
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `download multiple failing packages`(@TempDir tempDir: Path) {
|
|
val cmd =
|
|
CliPackageDownloader(
|
|
baseOptions =
|
|
CliBaseOptions(
|
|
moduleCacheDir = tempDir,
|
|
caCertificates = listOf(FileTestUtils.selfSignedCertificatePem),
|
|
testPort = server.port,
|
|
),
|
|
packageUris =
|
|
listOf(
|
|
PackageUri("package://localhost:0/badChecksum@1.0.0"),
|
|
PackageUri("package://bogus.domain/notAPackage@1.0.0"),
|
|
),
|
|
noTransitive = true,
|
|
)
|
|
assertThatCode { cmd.run() }
|
|
.hasMessage(
|
|
"""
|
|
Failed to download some packages.
|
|
|
|
Failed to download package://localhost:0/badChecksum@1.0.0 because:
|
|
Cannot download package `package://localhost:0/badChecksum@1.0.0` because the computed checksum does not match the expected checksum.
|
|
|
|
Computed checksum: "a6bf858cdd1c09da475c2abe50525902580910ee5cc1ff624999170591bf8f69"
|
|
Expected checksum: "intentionally bogus checksum"
|
|
Asset URL: "https://localhost:0/badChecksum@1.0.0/badChecksum@1.0.0.zip"
|
|
|
|
Failed to download package://bogus.domain/notAPackage@1.0.0 because:
|
|
Exception when making request `GET https://bogus.domain/notAPackage@1.0.0`:
|
|
Error connecting to host `bogus.domain`.
|
|
|
|
"""
|
|
.trimIndent()
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `download package, including transitive dependencies`(@TempDir tempDir: Path) {
|
|
CliPackageDownloader(
|
|
baseOptions =
|
|
CliBaseOptions(
|
|
moduleCacheDir = tempDir,
|
|
caCertificates = listOf(FileTestUtils.selfSignedCertificatePem),
|
|
testPort = server.port,
|
|
),
|
|
packageUris = listOf(PackageUri("package://localhost:0/birds@0.5.0")),
|
|
noTransitive = false,
|
|
)
|
|
.run()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip")).exists()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.json")).exists()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/fruit@1.0.5/fruit@1.0.5.zip")).exists()
|
|
assertThat(tempDir.resolve("package-2/localhost(3a)0/fruit@1.0.5/fruit@1.0.5.json")).exists()
|
|
}
|
|
}
|