dokka icon indicating copy to clipboard operation
dokka copied to clipboard

Javadoc exposes absolute paths in dokka-configuration.json

Open TWiStErRob opened this issue 11 months ago • 3 comments
trafficstars

Describe the bug

Just migrated to Dokka 2.0.0, and I was diffing the artifacts of publishToMavenLocal. I found that the new javadoc jar contains the absolute paths of the source files and classpaths.

This means the resulting artifacts are not reproducible.

There might be also a security risk as some companies use Dokka to generate javadoc for public APIs and publish them online. These could leak internal implementation details of their systems, and the paths could be used to learn about their build machines. This could in theory aid attackers to exploit vulnerabilities more easily.

Expected behaviour

Relative paths or paths with env vars or no paths at all?

(Note re relative paths: my Gradle and Project paths are on separate Windows drive letters, so there's no way to navigate between them with ../. Even if that was possible the depth of the folders would still make it not reproducible.)

Screenshots I replaced my local absolute paths with GRADLE_USER_HOME and PROJECT_CHECKOUT_DIR.

{
  "moduleName": "my-module",
  "moduleVersion": "<version>-SNAPSHOT",
  "outputDir": "%PROJECT_CHECKOUT_DIR%\\my\\module\\build\\dokka\\javadoc",
  "cacheRoot": null,
  "offlineMode": false,
  "sourceSets": [
    {
      "displayName": "jvm",
      "sourceSetID": {
        "scopeId": ":my:module",
        "sourceSetName": "main"
      },
      "classpath": [
        "%GRADLE_USER_HOME%\\caches\\8.8\\generated-gradle-jars\\gradle-api-8.8.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-ant-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-astbuilder-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-console-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-datetime-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-dateutil-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-groovydoc-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-json-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-nio-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-sql-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-templates-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-test-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\groovy-xml-3.0.21.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\javaparser-core-3.17.0.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\kotlin-reflect-1.9.22.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\kotlin-stdlib-1.9.22.jar",
        "%GRADLE_USER_HOME%\\wrapper\\dists\\gradle-8.8-all\\6gdy1pgp427xkqcjbxw3ylt6h\\gradle-8.8\\lib\\gradle-installation-beacon-8.8.jar",
        "%PROJECT_CHECKOUT_DIR%\\my\\module\\build\\classes\\java\\main",
        "%PROJECT_CHECKOUT_DIR%\\my\\module\\build\\classes\\kotlin\\main",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.jetbrains.kotlin\\kotlin-stdlib-jdk8\\1.4.32\\3302f9ec8a5c1ed220781dbd37770072549bd333\\kotlin-stdlib-jdk8-1.4.32.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.jetbrains.kotlin\\kotlin-reflect\\1.4.32\\ce852b166d97f0f1991b5130c2bb02e2ef6c554e\\kotlin-reflect-1.4.32.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.jetbrains.kotlin\\kotlin-stdlib-jdk7\\1.4.32\\3546900a3ebff0c43f31190baf87a9220e37b7ea\\kotlin-stdlib-jdk7-1.4.32.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.jetbrains.kotlin\\kotlin-stdlib\\1.4.32\\461367948840adbb0839c51d91ed74ef4a9ccb52\\kotlin-stdlib-1.4.32.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.gradle\\gradle-kotlin-dsl\\6.1.1\\4f811c43a0688fb76681c357033c734fa740d898\\gradle-kotlin-dsl-6.1.1.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\com.android.tools.build\\gradle\\8.6.1\\39f7fafdf840259a73a7107af8c64109086ed429\\gradle-8.6.1.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.jetbrains.kotlin\\kotlin-stdlib-common\\1.4.32\\ef50bfa2c0491a11dcc35d9822edbfd6170e1ea2\\kotlin-stdlib-common-1.4.32.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.jetbrains\\annotations\\13.0\\919f0dfe192fb4e063e7dacadee7f8bb9a2672a9\\annotations-13.0.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\com.android.tools.build\\builder\\8.6.1\\3ede92b2242a7a5b214479bd81c75c6c894308e8\\builder-8.6.1.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\com.android.tools.build\\builder-model\\8.6.1\\f4e5827bbddac07172f97f5d629911a4d49620a2\\builder-model-8.6.1.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\com.android.tools.build\\gradle-api\\8.6.1\\1dde4ab125287658b1793e4a023e6249e017d358\\gradle-api-8.6.1.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\com.android.tools.build\\manifest-merger\\31.6.1\\74d2b65c9e2b55d6f7de18cced38aa6c777f63d5\\manifest-merger-31.6.1.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\com.android\\zipflinger\\8.6.1\\de8e3267995699af356740cf562cbedb485f5763\\zipflinger-8.6.1.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\com.android.tools.build\\apksig\\8.6.1\\f005788487574c7d6ba23dea63bf8cb3a4f164a6\\apksig-8.6.1.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\com.android.tools.build\\apkzlib\\8.6.1\\d656b52facbb301b8bdc1e40a5ae008bcf335fe9\\apkzlib-8.6.1.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\com.squareup\\javawriter\\2.5.0\\81241ff7078ef14f42ea2a8995fa09c096256e6b\\javawriter-2.5.0.jar",
        "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.ow2.asm\\asm\\9.6\\aa205cf0a06dbd8e04ece91c0b37c3f5d567546a\\asm-9.6.jar"
      ],
      "sourceRoots": [
        "%PROJECT_CHECKOUT_DIR%\\my\\module\\src\\main\\kotlin"
      ],
      "dependentSourceSets": [
      ],
      "samples": [
      ],
      "includes": [
      ],
      "includeNonPublic": false,
      "reportUndocumented": false,
      "skipEmptyPackages": true,
      "skipDeprecated": false,
      "jdkVersion": 11,
      "sourceLinks": [
      ],
      "perPackageOptions": [
      ],
      "externalDocumentationLinks": [
        {
          "url": "https://docs.oracle.com/en/java/javase/11/docs/api/",
          "packageListUrl": "https://docs.oracle.com/en/java/javase/11/docs/api/element-list"
        },
        {
          "url": "https://kotlinlang.org/api/core/",
          "packageListUrl": "https://kotlinlang.org/api/core/package-list"
        }
      ],
      "languageVersion": null,
      "apiVersion": null,
      "noStdlibLink": false,
      "noJdkLink": false,
      "suppressedFiles": [
      ],
      "analysisPlatform": "jvm",
      "documentedVisibilities": [
        "PUBLIC"
      ]
    }
  ],
  "pluginsClasspath": [
    "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.jetbrains.dokka\\javadoc-plugin\\2.0.0\\602a87960edaa602969fa4922ad9efc02ed3a39d\\javadoc-plugin-2.0.0.jar",
    "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.jetbrains.dokka\\templating-plugin\\2.0.0\\2c817817579cd8c92ded6f33fd9e6b746ecf01c7\\templating-plugin-2.0.0.jar",
    "%GRADLE_USER_HOME%\\caches\\modules-2\\files-2.1\\org.jetbrains.dokka\\dokka-base\\2.0.0\\dcce26b10e9af3b3f2eba0403d6a9561e6da9098\\dokka-base-2.0.0.jar"
  ],
  "pluginsConfiguration": [
    {
      "fqPluginName": "org.jetbrains.dokka.base.DokkaBase",
      "serializationFormat": "JSON",
      "values": "{\"customAssets\":[],\"customStyleSheets\":[],\"separateInheritedMembers\":false,\"mergeImplicitExpectActualDeclarations\":false}"
    },
    {
      "fqPluginName": "org.jetbrains.dokka.versioning.VersioningPlugin",
      "serializationFormat": "JSON",
      "values": "{\"olderVersions\":[],\"renderVersionsNavigationOnAllPages\":true}"
    }
  ],
  "modules": [
  ],
  "failOnWarning": false,
  "delayTemplateSubstitution": false,
  "suppressObviousFunctions": true,
  "includes": [
  ],
  "suppressInheritedMembers": false,
  "finalizeCoroutines": false
}

To Reproduce gradlew dokkaGeneratePublicationJavadoc and inspect the javadoc jar.

Dokka configuration

plugins {
	id("org.jetbrains.dokka")
	id("org.jetbrains.dokka-javadoc")
}

Workaround (For this users have to notice that this is happening so that they can action it.)

See https://github.com/Kotlin/dokka/blob/v2.0.0/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt#L99-L106

Attempt 1

Follow docs...

tasks.withType<DokkaGenerateTask>().configureEach {
	@OptIn(InternalDokkaGradlePluginApi::class)
	dokkaConfigurationJsonFile.set(null as File?)
	// or
	dokkaConfigurationJsonFile.unset()
}

Tried also wrapping in afterEvaluate, neither worked.

Attempt 2

Delete file at the "right" time.

tasks.withType<DokkaGenerateTask>().configureEach {
	doLast {
		@OptIn(InternalDokkaGradlePluginApi::class)
		dokkaConfigurationJsonFile.orNull?.asFile?.delete()
	}
}

but this is way too hacky.

Attempt 3

Hail Mary... based on some random intuition.

tasks.withType<DokkaGenerateTask>().configureEach {
	@OptIn(InternalDokkaGradlePluginApi::class)
	dokkaConfigurationJsonFile.unsetConvention()
	// or
	dokkaConfigurationJsonFile.convention(null as RegularFile?)
}

Bingo!

Installation

  • Operating system: Windows 10
  • Build tool: Gradle v8.12 RC
  • Dokka version: 2.0.0

TWiStErRob avatar Dec 17 '24 01:12 TWiStErRob

Hi, thanks for the report. I agree that the dokka-configuration.json file should not be included in the final output. It's only intended for debugging purposes on a local or CI machine, and shouldn't be shared.

For some context: I recently changed the dokkaConfigurationJsonFile property to be an explicit task output to help with debugging tricky issues with KMP on CI. This is an unintended consequence I didn't anticipate.

To Reproduce gradlew dokkaGeneratePublicationJavadoc and inspect the javadoc jar.

The dokkaGeneratePublicationJavadoc task doesn't produce a JAR file (there's currently no official Dokka task that will produce a JAR). I assume your project has some custom Javadoc JAR task defined?

When I run the library-publishing-example, it doesn't include the dokka-configuration.json file in the resulting JAR, but that's because it specifically selects the task output directory using from(tasks.dokkaGeneratePublicationJavadoc.flatMap { it.outputDirectory }).

https://github.com/Kotlin/dokka/blob/fc574c855fb75a4fe30185aa9f12b74295b095d4/examples/gradle-v2/library-publishing-example/build.gradle.kts#L12-L16

However, I think it's too easy to make a mistake. I'll see if I can find a better way to prevent the config file from being accidentally shared as an output.

adam-enko avatar Dec 17 '24 13:12 adam-enko

Ah, I see, auto-output usage mine indeed!

It is coming from here: https://github.com/TWiStErRob/net.twisterrob.gradle/blob/dd867db6c0aee19cc75816823890d9be32f8f533/gradle/plugins/src/main/kotlin/net/twisterrob/gradle/build/publishing/withDokkaJar.kt

Used like this: https://github.com/TWiStErRob/net.twisterrob.gradle/blob/dd867db6c0aee19cc75816823890d9be32f8f533/gradle/plugins/src/main/kotlin/net/twisterrob/gradle/build/publishing/net.twisterrob.gradle.build.publish.gradle.kts#L52-L62

Since the param is defined as Object at https://github.com/gradle/gradle/blob/v8.11.1/platforms/jvm/plugins-java-base/src/main/java/org/gradle/api/plugins/internal/JvmPluginsHelper.java#L138

I guess I could do the selection myself as well, but you're right that it's easy to make this mistake if we use implicit outputs.

TWiStErRob avatar Dec 17 '24 14:12 TWiStErRob

The same happens for dokkaGeneratePublicationHtml, which I suspect is not a surprise, but thought was worth mentioning.

I am upgrading from Dokka 1.9.20 to 2.0.0 and was using the following configuration to add the javadoc artifact to Maven publications (artifact( javadocJar )).

val javadocJar by tasks.creating( Jar::class )
{
    archiveClassifier.set( "javadoc" )
    from( tasks.dokkaJavadoc )
}

When upgrading to Dokka 2.0.0 with DGP V2 enabled, I first tried using from( tasks.dokkaGenerate ), which results in an empty javadoc jar output. Then, from( tasks.dokkaGeneratePublicationHtml ), which results in output including the dokka-configuration.json file.

@TWiStErRob 's fix works 🙏 :

tasks.withType<DokkaGenerateTask>().configureEach {
    @OptIn( InternalDokkaGradlePluginApi::class )
    dokkaConfigurationJsonFile.convention( null as RegularFile? )
}

Whathecode avatar May 11 '25 13:05 Whathecode