Fix: use http.rewrites to configure the evaluator in message passing API (#1141)

This is a bugfix, where the `rewrites` option is currently ignored.

Also: return any illegal argument errors from creating the evaluator as
an error in the CreateEvaluatorResponse
This commit is contained in:
Daniel Chao
2025-07-24 07:30:31 -07:00
committed by GitHub
parent ae046a804b
commit 1c4fbe7c1c
6 changed files with 117 additions and 48 deletions

View File

@@ -183,49 +183,54 @@ class Server(private val transport: MessageTransport) : AutoCloseable {
} }
private fun createEvaluator(message: CreateEvaluatorRequest, evaluatorId: Long): BinaryEvaluator { private fun createEvaluator(message: CreateEvaluatorRequest, evaluatorId: Long): BinaryEvaluator {
val modulePaths = message.modulePaths ?: emptyList() try {
val resolver = ModulePathResolver(modulePaths) val modulePaths = message.modulePaths ?: emptyList()
val allowedModules = message.allowedModules?.map { Pattern.compile(it) } ?: emptyList() val resolver = ModulePathResolver(modulePaths)
val allowedResources = message.allowedResources?.map { Pattern.compile(it) } ?: emptyList() val allowedModules = message.allowedModules?.map { Pattern.compile(it) } ?: emptyList()
val rootDir = message.rootDir val allowedResources = message.allowedResources?.map { Pattern.compile(it) } ?: emptyList()
val env = message.env ?: emptyMap() val rootDir = message.rootDir
val properties = message.properties ?: emptyMap() val env = message.env ?: emptyMap()
val timeout = message.timeout val properties = message.properties ?: emptyMap()
val cacheDir = message.cacheDir val timeout = message.timeout
val httpClient = val cacheDir = message.cacheDir
with(HttpClient.builder()) { val httpClient =
message.http?.proxy?.let { proxy -> with(HttpClient.builder()) {
setProxy(proxy.address, proxy.noProxy ?: listOf()) message.http?.proxy?.let { proxy ->
proxy.address?.let(IoUtils::setSystemProxy) setProxy(proxy.address, proxy.noProxy ?: listOf())
proxy.noProxy?.let { System.setProperty("http.nonProxyHosts", it.joinToString("|")) } proxy.address?.let(IoUtils::setSystemProxy)
proxy.noProxy?.let { System.setProperty("http.nonProxyHosts", it.joinToString("|")) }
}
message.http?.caCertificates?.let(::addCertificates)
message.http?.rewrites?.let(::setRewrites)
buildLazily()
} }
message.http?.caCertificates?.let(::addCertificates) val dependencies =
buildLazily() message.project?.let { proj ->
} buildDeclaredDependencies(proj.projectFileUri, proj.dependencies, null)
val dependencies = }
message.project?.let { proj -> log("Got dependencies: $dependencies")
buildDeclaredDependencies(proj.projectFileUri, proj.dependencies, null) return BinaryEvaluator(
} StackFrameTransformers.defaultTransformer,
log("Got dependencies: $dependencies") SecurityManagers.standard(
return BinaryEvaluator( allowedModules,
StackFrameTransformers.defaultTransformer, allowedResources,
SecurityManagers.standard( SecurityManagers.defaultTrustLevels,
allowedModules, rootDir,
allowedResources, ),
SecurityManagers.defaultTrustLevels, httpClient,
rootDir, ClientLogger(evaluatorId, transport),
), createModuleKeyFactories(message, evaluatorId, resolver),
httpClient, createResourceReaders(message, evaluatorId, resolver),
ClientLogger(evaluatorId, transport), env,
createModuleKeyFactories(message, evaluatorId, resolver), properties,
createResourceReaders(message, evaluatorId, resolver), timeout,
env, cacheDir,
properties, dependencies,
timeout, message.outputFormat,
cacheDir, )
dependencies, } catch (e: IllegalArgumentException) {
message.outputFormat, throw ProtocolException(e.message ?: "Failed to create an evalutor. $e", e)
) }
} }
private fun createResourceReaders( private fun createResourceReaders(

View File

@@ -99,8 +99,8 @@ class ServerMessagePackDecoder(unpacker: MessageUnpacker) : BaseMessagePackDecod
getNullable(httpMap, "rewrites") getNullable(httpMap, "rewrites")
?.asMapValue() ?.asMapValue()
?.map() ?.map()
?.mapKeys { it.key.asStringValue().asString() } ?.mapKeys { URI(it.key.asStringValue().asString()) }
?.mapValues { it.value.asStringValue().asString() } ?.mapValues { URI(it.value.asStringValue().asString()) }
return Http(caCertificates, proxy, rewrites) return Http(caCertificates, proxy, rewrites)
} }

View File

@@ -48,8 +48,8 @@ class ServerMessagePackEncoder(packer: MessagePacker) : BaseMessagePackEncoder(p
packString("rewrites") packString("rewrites")
packMapHeader(rewrites.size) packMapHeader(rewrites.size)
for ((key, value) in rewrites) { for ((key, value) in rewrites) {
packString(key) packString(key.toString())
packString(value) packString(value.toString())
} }
} }
} }

View File

@@ -57,7 +57,7 @@ data class Http(
/** Proxy settings */ /** Proxy settings */
val proxy: Proxy?, val proxy: Proxy?,
/** HTTP rewrites */ /** HTTP rewrites */
val rewrites: Map<String, String>?, val rewrites: Map<URI, URI>?,
) { ) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true

View File

@@ -60,6 +60,26 @@ abstract class AbstractServerTest {
abstract val client: TestTransport abstract val client: TestTransport
private val blankCreateEvaluatorRequest =
CreateEvaluatorRequest(
requestId = 1,
http = null,
allowedModules = null,
allowedResources = null,
clientModuleReaders = null,
clientResourceReaders = null,
modulePaths = null,
env = null,
properties = null,
timeout = null,
rootDir = null,
cacheDir = null,
outputFormat = null,
project = null,
externalModuleReaders = null,
externalResourceReaders = null,
)
@Test @Test
fun `create and close evaluator`() { fun `create and close evaluator`() {
val evaluatorId = client.sendCreateEvaluatorRequest(123) val evaluatorId = client.sendCreateEvaluatorRequest(123)
@@ -931,6 +951,50 @@ abstract class AbstractServerTest {
) )
} }
@Test
fun `http rewrites`() {
val evaluatorId =
client.sendCreateEvaluatorRequest(
http =
Http(
caCertificates = null,
proxy = null,
rewrites = mapOf(URI("https://example.com/") to URI("https://example.example/")),
)
)
client.send(
EvaluateRequest(
1,
evaluatorId,
URI("repl:text"),
"res = import(\"https://example.com/foo.pkl\")",
"output.text",
)
)
val response = client.receive<EvaluateResponse>()
assertThat(response.error)
.contains(
"request was rewritten: https://example.com/foo.pkl -> https://example.example/foo.pkl"
)
}
@Test
fun `http rewrites -- invalid rule`() {
client.send(
blankCreateEvaluatorRequest.copy(
http =
Http(
caCertificates = null,
proxy = null,
rewrites = mapOf(URI("https://example.com") to URI("https://example.example/")),
)
)
)
val response = client.receive<CreateEvaluatorResponse>()
assertThat(response.error)
.contains("Rewrite rule must end with '/', but was 'https://example.com'")
}
private val ByteArray.debugYaml private val ByteArray.debugYaml
get() = MessagePackDebugRenderer(this).output.trimIndent() get() = MessagePackDebugRenderer(this).output.trimIndent()

View File

@@ -96,7 +96,7 @@ class ServerMessagePackCodecTest {
Http( Http(
proxy = Proxy(URI("http://foo.com:1234"), listOf("bar", "baz")), proxy = Proxy(URI("http://foo.com:1234"), listOf("bar", "baz")),
caCertificates = byteArrayOf(1, 2, 3, 4), caCertificates = byteArrayOf(1, 2, 3, 4),
rewrites = mapOf("https://foo.com" to "https://bar.com"), rewrites = mapOf(URI("https://foo.com/") to URI("https://bar.com/")),
), ),
externalModuleReaders = mapOf("external" to externalReader, "external2" to externalReader), externalModuleReaders = mapOf("external" to externalReader, "external2" to externalReader),
externalResourceReaders = mapOf("external" to externalReader), externalResourceReaders = mapOf("external" to externalReader),