Reading a JSON based Context parameter (potential security issue with Kotlin DSL sandbox environment)

Hey guys,

we create projects and buildTypes based on different build configurations and platforms out of a list. The list is atm part of the actual DSL and I want to be able to give this information as Json via Context Params so that you can easly switch the to be build configs and not to touch DSL code. It looks like that at the moment:

data class ProjectConf(
val name: String = "",
val targetPlatform: String = "Win64",
val targetConfiguration: String = "Development+Shipping"
)

[...]
var projectsList = listOf(
ProjectConf(
name = "WindowsNoEditor",
targetPlatform = "Win64",
targetConfiguration = "Development+Shipping"
),
ProjectConf(
name = "WindowsServer",
targetPlatform = "Win64",
targetConfiguration = "Development+Shipping",
),
ProjectConf(
name = "LinuxServer",
targetPlatform = "Linux",
targetConfiguration = "Development+Shipping",
),
)
[...]

We then iterate over the list and create the buildTypes and chain them together. This is what I did for the Json decoding (of a test string atm) on code side:

import kotlinx.serialization.json.*
import kotlinx.serialization.*

@Serializable
data class ProjectConf(
val name: String = "",
val targetPlatform: String = "Win64",
val targetConfiguration: String = "Development+Shipping",
)
[...]
val projects = Json.decodeFromString<ProjectConf>(""""
{"name":"foobar","targetPlatform":"foobar","targetConfiguration":"foobar"}
"""")

This is what I added to the pom.xml

<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-serialization-core</artifactId>
<version>1.2.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-serialization-json-jvm</artifactId>
<version>1.2.1</version>
<scope>compile</scope>
</dependency>

Generating the teamcity-configs leads to that runtime error:

[ERROR] Runtime error RootProjectId: kotlinx.serialization.internal.Platform_commonKt[91]: kotlinx.serialization.SerializationException: Serializer for class 'ProjectConf' is not found.
Mark the class as @Serializable or provide the serializer explicitly.
at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:91)
at kotlinx.serialization.internal.PlatformKt.platformSpecificSerializerNotRegistered(Platform.kt:29)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:60)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source)
at snapshot.SnapshotProject$1.invoke(Project.kt:139)
at snapshot.SnapshotProject$1.invoke(Project.kt:23)
at jetbrains.buildServer.configs.kotlin.v2019_2.Project.<init>(Project.kt:166)
at snapshot.SnapshotProject.<init>(Project.kt:23)
at Settings$1.invoke(settings.kts:59)
at Settings$1.invoke(settings.kts:5)

Since I annotated my data class with '@Serializable' I googled around but only found Android/Gradle enviroment related posts. I regards of Maven I just found https://github.com/cqfn/diKTat/blob/master/diktat-common/pom.xml but 'teamcity-configs-maven-plugin' doesn't support 'compilerPlugins' in 'configuration'. After playing around I end up with a "solution" where I added the dependencies directly to the 'teamcity-configs-maven-plugin' plugin section:

<build>
<sourceDirectory>${basedir}</sourceDirectory>
<plugins>
[...]
<plugin>
<groupId>org.jetbrains.teamcity</groupId>
<artifactId>teamcity-configs-maven-plugin</artifactId>
<version>${teamcity.dsl.version}</version>
[...]
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-serialization-json-jvm</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-serialization-core</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>
</plugin>

I think this brought me one step closer since I ran now into this call stack:

[ERROR] Error while generating TeamCity configs:
[ERROR] Runtime error RootProjectId: java.security.AccessControlContext[472]: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")
at java.base/java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
at java.base/java.security.AccessController.checkPermission(AccessController.java:897)
at java.base/java.lang.SecurityManager.checkPermission(SecurityManager.java:322)
at java.base/java.lang.Class.checkMemberAccess(Class.java:2847)
at java.base/java.lang.Class.getDeclaredFields(Class.java:2246)
at kotlinx.serialization.internal.PlatformKt.findObjectSerializer(Platform.kt:128)
at kotlinx.serialization.internal.PlatformKt.constructSerializerForGivenTypeArgs(Platform.kt:44)
at kotlinx.serialization.internal.PlatformKt.compiledSerializerImpl(Platform.kt:23)
at kotlinx.serialization.SerializersKt__SerializersKt.serializerOrNull(Serializers.kt:178)
at kotlinx.serialization.SerializersKt.serializerOrNull(Unknown Source)
at kotlinx.serialization.SerializersKt__SerializersKt.serializerByKTypeImpl$SerializersKt__SerializersKt(Serializers.kt:83)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:59)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source)

Can you confirm that such serialization is not possible due to security/sandbox constrainst? Also can you maybe help me with the actual dependency setup?

Cheers,

Flo

6 comments
Comment actions Permalink

Hey Florian Oeser, I have the exact same issue as you. Did you find any resolution to this?

0
Comment actions Permalink

Hey Gary,

sadly not, its a sandbox limitation. You can also follow this https://youtrack.jetbrains.com/issue/TW-59901 but sadly there is not so much movement/interest from JB at the moment.

-Flo

0
Comment actions Permalink

Hey Florian Oeser,

FYI, we did get a response from a JB guy in https://youtrack.jetbrains.com/issue/TW-72912 saying that they had gotten gson library to work instead of kotlinx (I work with Miguel mentioned in that thread). You can try following that too. Unfortunately, the sample code provided doesn't work for us yet but maybe they will respond further.

Regards,

Gary

0
Comment actions Permalink

Hey Gary,

thanks for letting me know, will follow that as well. But I don't have so much hope because regardless which actual framework/library (kotlinx, gson etc.) you use in the end it will no be able to execute (runtime reflection) due to the sandbox constraints. 

I guess when Anton Zamolotskikh mentioned that they got it to work with gson he was just referring to solve the actual dependency/plugin problem. But we'll see :)

0
Comment actions Permalink

Hey Florian Oeser,

We got a follow up reply from Anton Zamolotskikh confirming that due to sandboxing in the TeamCity DSL engine, they do not support reflection calls from DSL code BUT also indicating how to use Gson or a similar library without reflection to parse JSON. The code below works for us now.

import com.google.gson.Gson
import com.google.gson.JsonObject
var gson = Gson()
val parsedJson = gson.fromJson(strJson, JsonObject::class.java)
val myValue = parsedJson.get("myJsonAttributeName").toString()

 

Another possibility: according to https://youtrack.jetbrains.com/issue/TW-53284 it looks like in the 2021.2 release that will be available in Oct they are adding a property that allows you to disable sandboxing for Kotlin DSL, so maybe you might prefer to wait for that either.

0
Comment actions Permalink

Hey Gary,

thx for the update and the hint with the upcoming property, sounds great! 

-Flo

0

Please sign in to leave a comment.