-
Notifications
You must be signed in to change notification settings - Fork 30
Introduce new Android artifact distribution strategy #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
47f78d9
Prepare for repository conversion into a workspace
complexspaces be4d9b4
Introduce new Cargo workspace
complexspaces 5ea4c11
Add note about possible issues due to Proguard optimizing out the And…
complexspaces ca372c9
Distribute Android component through pre-built Maven local repository
complexspaces File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,72 +1,7 @@ | ||
[package] | ||
name = "rustls-platform-verifier" | ||
version = "0.1.0" | ||
authors = ["ComplexSpaces <complexspacescode@gmail.com>", "1Password"] | ||
description = "rustls-platform-verifier supports verifying TLS certificates in rustls with the operating system verifier" | ||
keywords = ["tls", "certificate", "verification", "os", "native"] | ||
repository = "https://github.com/1Password/rustls-platform-verifier" | ||
license = "MIT OR Apache-2.0" | ||
edition = "2021" | ||
rust-version = "1.64.0" | ||
|
||
exclude = [ | ||
"android/.run", | ||
"android/gradle/**", | ||
"android/gradle*", | ||
"android/settings.gradle", | ||
"android/src/androidTest", | ||
[workspace] | ||
members = [ | ||
"android-release-support", | ||
"rustls-platform-verifier", | ||
] | ||
|
||
[lib] | ||
name = "rustls_platform_verifier" | ||
# Note: The `cdylib` specification is for testing only. The shared library | ||
# is not expected to have a stable API. | ||
crate-type = ["cdylib", "rlib"] | ||
|
||
[features] | ||
# Enables a C interface to use for testing where `cargo` can't be used. | ||
# This feature is not stable, nor is the interface exported when it is enabled. | ||
# Do not rely on this or use it in production. | ||
ffi-testing = ["android_logger"] | ||
# Enables APIs that expose lower-level verifier types for debugging purposes. | ||
dbg = [] | ||
# Enables `log::debug` base64-encoded logging of all end-entity certificates processed | ||
# by the platform's verifier. | ||
cert-logging = ["base64"] | ||
# Used for nicely documenting the Android-specific APIs. This feature is not stable. | ||
docsrs = ["jni", "once_cell"] | ||
|
||
[dependencies] | ||
rustls = { version = "0.21", features = ["dangerous_configuration", "tls12", "logging"] } | ||
log = { version = "0.4" } | ||
base64 = { version = "0.21", optional = true } # Only used when the `cert-logging` feature is enabled. | ||
jni = { version = "0.19", default-features = false, optional = true } # Only used during doc generation | ||
once_cell = { version = "1.9", optional = true } # Only used during doc generation. | ||
|
||
[target.'cfg(target_os = "linux")'.dependencies] | ||
rustls-native-certs = "0.6" | ||
once_cell = "1.9" | ||
webpki = { package = "rustls-webpki", version = "0.101", features = ["alloc", "std"] } | ||
|
||
[target.'cfg(target_os = "android")'.dependencies] | ||
jni = { version = "0.19", default-features = false } | ||
webpki = { package = "rustls-webpki", version = "0.101", features = ["alloc", "std"] } | ||
once_cell = "1.9" | ||
android_logger = { version = "0.13", optional = true } # Only used during testing. | ||
|
||
[target.'cfg(target_arch = "wasm32")'.dependencies] | ||
once_cell = "1.9" | ||
webpki-roots = "0.25" | ||
|
||
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] | ||
core-foundation = "0.9" | ||
core-foundation-sys = "0.8" | ||
security-framework = { version = "2.6", features = ["OSX_10_14"] } | ||
security-framework-sys = { version = "2.4", features = ["OSX_10_14"] } | ||
|
||
[target.'cfg(windows)'.dependencies] | ||
winapi = { version = "0.3", features = ["wincrypt", "winerror"] } | ||
|
||
[package.metadata.docs.rs] | ||
rustdoc-args = ["--cfg", "docsrs"] | ||
features = ["dbg", "docsrs"] | ||
resolver = "2" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# How-to release `rustls-platform-verifier` | ||
|
||
This document records the steps to publish new versions of the crate since it requires non-trivial preparation and ordering | ||
that needs to be remembered due to the Android component's distribution. | ||
|
||
## Steps | ||
|
||
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 | ||
cpu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* 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 --alow-dirty` | ||
<!--- | ||
TODO: Consider instead making tag-specific commits that check-in the artifacts. For now, the | ||
seamless AAR reproducibility makes this a non-issue. | ||
--> | ||
* `--allow-dirty` is required because we don't check-in the generated Maven local repository at this time. | ||
6. (Optional) Inspect extracted archive to ensure the local Maven repository artifacts are present | ||
cpu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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. Publish the Android artifacts' new version: `cargo publish -p rustls-platform-verifier-android --alow-dirty` | ||
3. Commit main crate's version increase on the release branch | ||
4. 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. | ||
|
||
See the Rustls repo [RELEASING] guidance for more information (e.g. on best practices for creating a GitHub release with a changelog). | ||
|
||
[RELEASING]: https://github.com/rustls/rustls/blob/main/RELEASING.md |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
[package] | ||
name = "rustls-platform-verifier-android" | ||
version = "0.1.0" | ||
description = "The internal JVM support component of the rustls-platform-verifier crate. You shouldn't depend on this directly." | ||
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] |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<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> | ||
<artifactId>rustls-platform-verifier</artifactId> | ||
<version>$VERSION</version> | ||
<packaging>aar</packaging> | ||
<description>The internal JVM support component of the rustls-platform-verifier Rust crate</description> | ||
</project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
//! # rustls-platform-verifier-android | ||
//! | ||
//! This crate is an implementation detail of the actual [rustls-platform-verifier](https://github.com/rustls/rustls-platform-verifier) crate. | ||
//! | ||
//! It contains no Rust code and is solely intended as a convenient delivery mechanism for the supporting Kotlin code that the main crate | ||
//! requires to perform TLS certificate validation using Android's APIs. | ||
//! | ||
//! Other crates should not directly depend on this crate in any way, as nothing about it is considered stable and it is probably useless elsewhere. | ||
//! | ||
//! ## Details | ||
//! | ||
//! Note: Everything in this section is subject to change at any time. Semver may not be followed. | ||
//! | ||
//! ### Why? | ||
//! | ||
//! It was the best middle ground between several tradeoffs. The important ones, in priority order, are: | ||
//! - Automatically keeping component versions in sync | ||
//! - Allowing well-tested and well-known `cargo` dependency management patterns to apply everywhere | ||
//! - Providing a smooth developer experience as an Android consumer of `rustls-platform-verifier` | ||
//! | ||
//! Firstly, what alternatives are available for distributing the component? The other two known are source distribution in some form (here, it will be through crates.io) | ||
//! and Maven Central. Starting with the first, its become infeasible due to toolchain syncing requirements. If the Android component is | ||
//! built as part of the host app's Gradle build, then it becomes subject to any Gradle or Android Gradle Plugin incompatibilities/requirements. In practice this means | ||
//! the AGP version between this project and the main application have to match all the time. Sometimes this works, but it becomes challenging/unfeasible | ||
//! during yearly toolchain/SDK upgrades and is not maintainable long term. Note that this is the _only_ option in this section which retains compatibility | ||
//! with Cargo's Git dependency patching. | ||
//! | ||
//! Next, Maven Central. This is considered the standard way of distributing public Android dependencies. There are two downsides to this | ||
//! approach: version synchronization and publishing overhead. Version syncing is the hardest part: There's not a good way to know what version | ||
//! a crate is that doesn't hurt the Cargo part of the build or damage functionality. So instead of making assumptions at runtime, we would need to do | ||
//! clunky and manual version counting with an extra error case. Less importantly, the admin overhead of Maven Central is non-zero so its good to avoid | ||
//! if possible for such a small need. | ||
//! | ||
//! It is also worth calling out a third set of much worse options: requiring users to manually download and install the Android component | ||
//! on each update, which magnifies the version syncing problem with lots of user overhead and then deleting the component outright. A rewrite | ||
//! could be done with raw JNI calls, but this would easily be 3x the size of the existing implementation and require huge amounts of `unsafe` | ||
//! to review then audit. | ||
//! | ||
//! ### The solution | ||
//! | ||
//! The final design was built to avoid the pitfalls the previous two options mentioned. To build it, we rely on CI and packaging scripts to build | ||
//! the Android component into a prebuilt AAR file before creating a release. Next, a [on-disk Maven repository](https://maven.apache.org/repositories/local.html) | ||
//! is hosted inside of this repository. Only the unchanging file structure of it is kept checked-in, to avoid churn. The remaining parts are filled in | ||
//! during the packaging/release process, before being included in `cargo package` via an `include` Cargo.toml directive. Finally, once the repository has had | ||
//! its artifacts added the crate containing the Maven repository is published to crates.io. Then, the main crate ensures it's downloaded when an Android target | ||
//! is compiled via a platform-specific dependency. | ||
//! | ||
//! On [the Gradle side](https://github.com/rustls/rustls-platform-verifier/tree/main#gradle-setup), we include a very small snippet of code for users to include in their `settings.gradle` file | ||
//! to dynamically locate the local maven repository on disk automatically based off Cargo's current version of it. The script is configuration cache friendly and | ||
//! doesn't impact performance either. When the script is run, it finds the cargo-cached download of the crate and tells Gradle it can find the Android component there | ||
//! when it gets sourced into the hosting application's build tree. | ||
//! | ||
//! Assuming a properly configured Gradle project, the slow (~500ms) script should only run once per Gradle sync while the `android-release-support` crate | ||
//! remains untouched. This is due to the configuration cache previously mentioned and is what ensures performance on-par with a "normal" Maven repository. | ||
//! Upon any version updates (semver, Git refs, etc), the change will be detected as-intended by Gradle, break the cache, and the project will update the dependency reference to the new AAR file. | ||
//! | ||
//! ### Precompiled artifacts? | ||
//! | ||
//! For some, the notion of shipping something pre-compiled with an existing source distribution might seem incorrect, or insecure. However in this specific case, | ||
//! putting aside the fact shipping Kotlin code doesn't work (see above), there are many reasons this isn't the case: | ||
//! - Shipping pre-compiled artifacts is normal in the Java ecosystem. Maven Central and other package repositories do the same thing and serve `.jar` downloads. | ||
//! - Those not using Android will never download the pre-compiled AAR file. | ||
//! - The artifacts are incredibly easy to reproduce given an identical compilation toolchain. | ||
//! - The artifacts are not native executables, or raw `.jar` files, so they can't be accidentally executed on a host system. | ||
//! | ||
//! ## Summary | ||
//! | ||
//! In summary, the selected distribution method avoids most of the previous pitfalls while still balancing a good experience for `cargo` and Gradle users. Some of its | ||
//! positive properties include: | ||
//! - Full compatibility with Cargo's dependency management, including Git patching[^1] | ||
//! - No version checking or synchronization required | ||
//! - Painless and harmless to integrate into an Android app's build system | ||
//! - Low maintenance for the main crate maintainers' | ||
//! | ||
//! [^1]: The Git reference being used must have the local maven repository built and checked-in first. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.