Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ jobs:
java-version: '17'

- name: Run Android tests
uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d # 2.33.0
uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # 2.38.0
with:
api-level: 28 # Android 9, Pie.
arch: x86_64
Expand Down
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
/android/verification/

# Ignore all generated Maven local repository files and folders
/android-release-support/maven/pom.xml
/android-release-support/maven/rustls/rustls-platform-verifier/**/
/android-release-support/maven/rustls/rustls-platform-verifier/maven-metadata-local.xml
/android-release-support/maven/org/rustls/rustls-platform-verifier/*
# These two must be kept since the state must be shared between normal branches and the Maven archive one.
!/android-release-support/maven/org/rustls/rustls-platform-verifier/maven-metadata.xml
!/android-release-support/maven/org/rustls/rustls-platform-verifier/maven-metadata-local.xml

# Nix
/result
207 changes: 77 additions & 130 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,83 +113,70 @@ let config = ClientConfig::builder_with_provider(arc_crypto_provider)
### Android
Some manual setup is required, outside of `cargo`, to use this crate on Android. In order to
use Android's certificate verifier, the crate needs to call into the JVM. A small Kotlin
component must be included in your app's build to support `rustls-platform-verifier`. If distributing a library, that component will need to be bundled into your release jar
[as it is not yet available on Maven](https://github.com/rustls/rustls-platform-verifier/issues/115).
component must be included in your app's build to support `rustls-platform-verifier`.

#### Gradle Setup

`rustls-platform-verifier` bundles the required native components in the crate, but the project must be setup to locate them
`rustls-platform-verifier` distributes the required native components in a Maven-compatible format via GitHub, but the project must be setup to locate them
automatically and correctly. These steps assume you are using `.gradle` Groovy files because they're the most common, but if you are using
Kotlin scripts (`.gradle.kts`) for configuration instead, an example snippet is included towards the end of this section.

Inside of your project's `build.gradle` file, add the following code and Maven repository definition. If applicable, this should only be the one "app" sub-project that
will actually be using this crate at runtime. With multiple projects running this, your Gradle configuration performance may degrade.
Each snippet includes a [`ValueSource`](https://docs.gradle.org/current/javadoc/org/gradle/api/provider/ValueSource.html) implementation that obtains a
Cargo-synchronized dependency version performantly, and is also friendly to Gradle's configuration cache. The version can be be selected manually instead,
but runtime crashes may occur if a SemVer incompatible version is used.

Inside of your project's `build.gradle` file, add the following code and Maven repository definition:

<details>

<summary>App Snippets</summary>

`$PATH_TO_DEPENDENT_CRATE` is the relative path to the Cargo manifest (`Cargo.toml`) of any crate in your workspace that depends on `rustls-platform-verifier` from
the location of your `build.gradle` file:
`$PATH_TO_LOCK_FILE` is the relative path to the Cargo lockfile of your crate or workspace (`Cargo.lock`).

```groovy
import groovy.json.JsonSlurper

// ...Your own script code could be here...

repositories {
// ... Your other repositories could be here...
maven {
url = findRustlsPlatformVerifierProject()
metadataSources.artifact()
url = "https://github.com/rustls/rustls-platform-verifier/raw/maven-archive/android-release-support/maven/"
}
}

String findRustlsPlatformVerifierProject() {
def dependencyText = providers.exec {
it.workingDir = new File("../")
commandLine("cargo", "metadata", "--format-version", "1", "--filter-platform", "aarch64-linux-android", "--manifest-path", "$PATH_TO_DEPENDENT_CRATE/Cargo.toml")
}.standardOutput.asText.get()
abstract class RustlsVersion implements ValueSource<String, RustlsVersion.Params> {
interface Params extends ValueSourceParameters {
RegularFileProperty getLockFile()
}

def dependencyJson = new JsonSlurper().parseText(dependencyText)
def manifestPath = file(dependencyJson.packages.find { it.name == "rustls-platform-verifier-android" }.manifest_path)
return new File(manifestPath.parentFile, "maven").path
static final String CRATE_NAME = "rustls-platform-verifier-android"

@Override
String obtain() {
def lockFile = parameters.lockFile.get().asFile
def lines = lockFile.readLines()
def idx = lines.findIndexOf { it.trim() == "name = \"$CRATE_NAME\"" }
def version = idx < 0 ? null : lines.drop(idx + 1)
.find { it.stripLeading().startsWith("version = ") }
?.find(/"([^"]*)"/) { match, v -> v }
if (!version) throw new GradleException("$CRATE_NAME not found in $lockFile")
return version
}
}
```

Then, wherever you declare your dependencies, add the following:
```groovy
implementation "rustls:rustls-platform-verifier:latest.release"
```

</details>

<details>
<summary>Library Snippets</summary>

```groovy
import groovy.json.JsonSlurper

// ...Your own script code could be here...

File findRustlsPlatformVerifierClasses() {
def dependencyText = providers.exec {
it.workingDir = new File("../")
commandLine("cargo", "metadata", "--format-version", "1")
}.standardOutput.asText.get()
def rustlsPlatformVerifierVersion = providers.of(RustlsVersion) { spec ->
spec.parameters.lockFile.set(layout.projectDirectory.file($PATH_TO_LOCK_FILE))
}

def dependencyJson = new JsonSlurper().parseText(dependencyText)
def manifestFile = file(dependencyJson.packages.find { it.name == "rustls-platform-verifier-android" }.manifest_path)
return new File(manifestFile.parentFile, "classes.jar")
configurations.configureEach { configuration ->
configuration.resolutionStrategy.eachDependency { details ->
if (details.requested.group == "org.rustls" && details.requested.name == "rustls-platform-verifier") {
details.useVersion(rustlsPlatformVerifierVersion.get())
details.because("native component version must be identical to version of ${RustlsVersion.CRATE_NAME}")
}
}
}
```

Then, wherever you declare your dependencies, add the following:
```groovy
implementation files(findRustlsPlatformVerifierClasses())
implementation "rustls:rustls-platform-verifier"
```

</details>
The dependency intentionally has no static version, it is only resolved dynamically at configuration time by the build script.

Cargo automatically handles finding the downloaded crate in the correct location for your project. It also handles updating the version when
new releases of `rustls-platform-verifier` are published. If you only use published releases, no extra maintenance should be required.
Expand All @@ -199,49 +186,51 @@ implementation part can be located on-disk.

##### Kotlin and Gradle

<details>
<summary>Kotlin script App example</summary>

`build.gradle.kts`:
```kotlin
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive

buildscript {
dependencies {
classpath(libs.kotlinx.serialization.json)
}
}

repositories {
rustlsPlatformVerifier()
maven {
url = uri("https://github.com/rustls/rustls-platform-verifier/raw/maven-archive/android-release-support/maven/")
}
}

fun RepositoryHandler.rustlsPlatformVerifier(): MavenArtifactRepository {
@Suppress("UnstableApiUsage")
val manifestPath = let {
val dependencyJson = providers.exec {
workingDir = File(project.rootDir, "../")
commandLine("cargo", "metadata", "--format-version", "1", "--filter-platform", "aarch64-linux-android", "--manifest-path", "$PATH_TO_DEPENDENT_CRATE/Cargo.toml")
}.standardOutput.asText

val path = Json.decodeFromString<JsonObject>(dependencyJson.get())
.getValue("packages")
.jsonArray
.first { element ->
element.jsonObject.getValue("name").jsonPrimitive.content == "rustls-platform-verifier-android"
}.jsonObject.getValue("manifest_path").jsonPrimitive.content

File(path)
abstract class RustlsVersion : ValueSource<String, RustlsVersion.Params> {
interface Params : ValueSourceParameters {
val lockFile: RegularFileProperty
}

companion object {
const val CRATE_NAME = "rustls-platform-verifier-android"
}

override fun obtain(): String {
val version = parameters.lockFile.get().asFile.readLines().let { lines ->
val nameIdx = lines.indexOfFirst { it.trim() == "name = \"$CRATE_NAME\"" }
if (nameIdx < 0) {
null
} else {
lines.drop(nameIdx + 1)
.firstOrNull { it.trimStart().startsWith("version = ") }
?.substringAfter('"', "")
?.substringBefore('"', "")
?.takeIf { it.isNotEmpty() }
}
}
return version?: error("$CRATE_NAME not found in Cargo.lock")
}
}

val rustlsPlatformVerifierVersion = providers.of(RustlsVersion::class.java) {
parameters.lockFile.set(layout.projectDirectory.file($PATH_TO_LOCK_FILE))
}

return maven {
url = uri(File(manifestPath.parentFile, "maven").path)
metadataSources.artifact()
configurations.configureEach {
resolutionStrategy.eachDependency {
if (requested.group == "org.rustls" && requested.name == "rustls-platform-verifier") {
useVersion(rustlsPlatformVerifierVersion.get())
because("native component version must be identical to version of ${RustlsVersion.CRATE_NAME}")
}
}
}

Expand All @@ -253,51 +242,9 @@ dependencies {

`libs.version.toml`:
```toml
# We always use the latest release because `cargo` keeps it in sync with the associated Rust crate's version.
rustls-platform-verifier = { group = "rustls", name = "rustls-platform-verifier", version = "latest.release" }
```
</details>

<details>
<summary>Kotlin script Library example</summary>

`build.gradle.kts`:
```kotlin
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive

buildscript {
dependencies {
classpath(libs.kotlinx.serialization.json)
}
}

fun findRustlsPlatformVerifierClasses(): File {
val dependencyJson = providers.exec {
workingDir = File(project.rootDir, "../")
commandLine("cargo", "metadata", "--format-version", "1")
}.standardOutput.asText

val path = Json.decodeFromString<JsonObject>(dependencyJson.get())
.getValue("packages")
.jsonArray
.first { element ->
element.jsonObject.getValue("name").jsonPrimitive.content == "rustls-platform-verifier-android"
}.jsonObject.getValue("manifest_path").jsonPrimitive.content

val manifestFile = File(path)
return File(manifestFile.parentFile, "classes.jar")
}

dependencies {
implementation(files(findRustlsPlatformVerifierClasses()))
}
# We keep the dependency unversioned because its version is selected dynamically during configuration.
rustls-platform-verifier = { group = "rustls", name = "rustls-platform-verifier" }
```
</details>

#### Proguard

Expand Down
28 changes: 11 additions & 17 deletions admin/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,25 @@ In the release preparation PR, the releaser may include the following checklist

1. Update main crate's version in `rustls-platform-verifier/Cargo.toml`.
2. If any non-test changes have been made to the `android` directory since the last release:
1. Update Android artifact version in `android-release-support/Cargo.toml`
2. Bump dependency version of the Android support crate in `rustls-platform-verifier/Cargo.toml` to match the new one
3. Commit version increase changes on the release branch
1. Update Android artifact version in `android-release-support/Cargo.toml`, and in the main crate if creating an incompatible SemVer release.
2. Commit version increase changes on the release branch
* We typically name these branches `rel-xxx` where `xxx` is the major version.
* We typically leave these branches around for future maintenance releases.
4. Run `ci/package_android_release.sh` in a UNIX compatible shell
5. (Optional) `cargo publish -p rustls-platform-verifier-android --dry-run --allow-dirty`
* `--allow-dirty` is required because we don't check-in the generated Maven local repository.
6. (Optional) Inspect extracted archive to ensure the local Maven repository artifacts are present
1. Un-tar the `rustls-platform-verifier-android-*.crate` file inside of `target/package`.
2. Verify `maven/rustls/rustls-platform-verifier` contains a single `*.RELEASE` directory and that contains a `.aar` file.
3. (Optional) If the releaser has an external Gradle project that uses the configuration from the README, paste the path to the
unzipped package's `Cargo.toml` as a replacement for the `manifestPath` variable. Run a Gradle Sync and observe everything works.
7. **Ensure that all version changes are committed to the correct branch before proceeding**. All version increases should be checked in prior
3. Run `ci/package_android_release.sh` in a UNIX compatible shell
4. Commit the Maven metadata updates on their own: `git commit -am "Bump Maven release to x.x.x"`. Copy the new commit's short ID.
5. **Ensure that all version changes are committed to the correct branch before proceeding**. All version increases should be checked in prior
to publishing on crates.io.
8. Publish the Android artifacts' new version: `cargo publish -p rustls-platform-verifier-android --allow-dirty`
6. Checkout the Maven storage branch: `git checkout maven-archive`. The newly built artifacts are now ready to check in.
7. Add the new artifacts to storage: `git add . && git commit -m "Prepare Maven release x.x.x"`
8. Sync the Maven metadata to make the new artifacts visible: `git cherry-pick $MAVEN_BUMP_COMMIT_ID`
9. Publish the new changes:
* `git push && git checkout rel-xxx`
* Publish the new Android marker version: `cargo publish -p rustls-platform-verifier-android`

3. Commit main crate's version increase on the release branch
4. **Ensure that all version changes are committed to the correct branch before proceeding**. All version increases should be checked in prior
to publishing on crates.io.
5. Publish the main crate's new version: `cargo publish -p rustls-platform-verifier`
* Do **not** use `--allow-dirty` for the main crate. Only the Android component requires it and a dirty workspace elsewhere is an error.
6. Follow the remaining steps in [RELEASING] to create the appropiate version tag.
7. If a new Android component release was made: Before publishing the GitHub release, run `./ci/archive_android_release.sh` to create a reproducible archive
containing the Android Maven components that were just published to crates.io. After creating the archive, upload it as an additional release artifact on GitHub.
Then, finish the release creation like normal.

[RELEASING]: https://github.com/rustls/rustls/blob/main/RELEASING.md
5 changes: 0 additions & 5 deletions android-release-support/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,8 @@ repository = "https://github.com/rustls/rustls-platform-verifier"
license = "MIT OR Apache-2.0"
edition = "2021"

# Explicitly include the Maven local repository for the Android component.
# While not checked into the repository, it is generated for releases and other contexts.
include = [
"src/*",
"maven/pom.xml",
"maven/rustls/rustls-platform-verifier/**/",
"maven/rustls/rustls-platform-verifier/maven-metadata-local.xml",
]

[dependencies]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>org.rustls</groupId>
<artifactId>rustls-platform-verifier</artifactId>
<versioning>
<release>0.1.1</release>
<versions>
<version>0.1.0</version>
<version>0.1.1</version>
</versions>
<lastUpdated>20240729132246</lastUpdated>
</versioning>
</metadata>
Empty file.
2 changes: 1 addition & 1 deletion android-release-support/pom-template.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>rustls</groupId>
<groupId>org.rustls</groupId>
<artifactId>rustls-platform-verifier</artifactId>
<version>$VERSION</version>
<packaging>aar</packaging>
Expand Down
Loading
Loading