From c8e129be161dc829065e3079507804c1e1d027ea Mon Sep 17 00:00:00 2001 From: BlackDex Date: Fri, 6 Oct 2023 16:06:00 +0200 Subject: [PATCH] Small updates - Updated to rust 1.73.0 - Updated crates - Updated documentation - Added a bake.sh script to make baking easier --- Cargo.lock | 60 +++++++++---------- Cargo.toml | 11 ++-- docker/DockerSettings.yaml | 4 +- docker/Dockerfile.alpine | 11 ++-- docker/Dockerfile.debian | 5 +- docker/Dockerfile.j2 | 3 +- docker/README.md | 118 ++++++++++++++++++++++++++++++++++++- docker/bake.sh | 25 ++++++++ docker/docker-bake.hcl | 79 ++++++++++++++++++++++++- rust-toolchain.toml | 2 +- 10 files changed, 263 insertions(+), 55 deletions(-) create mode 100755 docker/bake.sh diff --git a/Cargo.lock b/Cargo.lock index 89a51247836..3fcd09a70e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,7 +232,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -249,7 +249,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -399,9 +399,9 @@ checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -720,14 +720,14 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] name = "diesel" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53c8a2cb22327206568569e5a45bb5a2c946455efdd76e24d15b7e82171af95e" +checksum = "2268a214a6f118fce1838edba3d1561cf0e78d8de785475957a580a7f8c69d33" dependencies = [ "bitflags 2.4.0", "byteorder", @@ -752,7 +752,7 @@ dependencies = [ "diesel_table_macro_syntax", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -782,7 +782,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" dependencies = [ - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -845,7 +845,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1040,7 +1040,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1843,7 +1843,7 @@ checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1922,7 +1922,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2034,7 +2034,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2083,7 +2083,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2203,9 +2203,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c" dependencies = [ "unicode-ident", ] @@ -2218,7 +2218,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "version_check", "yansi 1.0.0-rc.1", ] @@ -2352,7 +2352,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2539,7 +2539,7 @@ dependencies = [ "proc-macro2", "quote", "rocket_http", - "syn 2.0.37", + "syn 2.0.38", "unicode-xid", ] @@ -2783,7 +2783,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2987,9 +2987,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -3060,7 +3060,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -3154,7 +3154,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -3324,7 +3324,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -3666,7 +3666,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -3700,7 +3700,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3879,9 +3879,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "037711d82167854aff2018dfd193aa0fef5370f456732f0d5a0c59b0f1b4b907" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 9cfc7145a0d..e9206598a23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "vaultwarden" version = "1.0.0" authors = ["Daniel GarcĂ­a "] edition = "2021" -rust-version = "1.70.0" +rust-version = "1.71.1" resolver = "2" repository = "https://github.com/dani-garcia/vaultwarden" @@ -75,7 +75,7 @@ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" # A safe, extensible ORM and Query builder -diesel = { version = "2.1.2", features = ["chrono", "r2d2"] } +diesel = { version = "2.1.3", features = ["chrono", "r2d2"] } diesel_migrations = "2.1.0" diesel_logger = { version = "0.3.0", optional = true } @@ -141,6 +141,9 @@ cookie_store = "0.19.1" # Used by U2F, JWT and PostgreSQL openssl = "0.10.57" +# Set openssl-sys fixed to v0.9.92 to prevent building issues with musl, arm and 32bit pointer width +# It will force add a dynamically linked library which prevents the build from being static +openssl-sys = "=0.9.92" # CLI argument parsing pico-args = "0.5.0" @@ -163,10 +166,6 @@ argon2 = "0.5.2" # Reading a password from the cli for generating the Argon2id ADMIN_TOKEN rpassword = "7.2.0" -# Set openssl-sys fixed to v0.9.92 to prevent building issues with musl, arm and 32bit pointer width -# It will force add a dynamically linked library which prevents the build from being static -openssl-sys = "=0.9.92" - [patch.crates-io] rocket = { git = 'https://github.com/SergioBenitez/Rocket', rev = 'ce441b5f46fdf5cd99cb32b8b8638835e4c2a5fa' } # v0.5 branch diff --git a/docker/DockerSettings.yaml b/docker/DockerSettings.yaml index b0be283f74d..2ad1eb1460a 100644 --- a/docker/DockerSettings.yaml +++ b/docker/DockerSettings.yaml @@ -1,7 +1,7 @@ --- vault_version: "v2023.8.2" -vault_image_digest: "sha256:b361e79309ef2c4368f880f350166daade41eb0927a9adf376c76e3713027252" # v2023.8.2 -rust_version: 1.72.1 # Rust version to be used +vault_image_digest: "sha256:b361e79309ef2c4368f880f350166daade41eb0927a9adf376c76e3713027252" +rust_version: 1.73.0 # Rust version to be used debian_version: bookworm # Debian release name to be used alpine_version: 3.18 # Alpine version to be used # For which platforms/architectures will we try to build images diff --git a/docker/Dockerfile.alpine b/docker/Dockerfile.alpine index f9307e8928f..77742c35b00 100644 --- a/docker/Dockerfile.alpine +++ b/docker/Dockerfile.alpine @@ -31,10 +31,10 @@ FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:b361e79309ef2 ########################## ALPINE BUILD IMAGES ########################## ## NOTE: The Alpine Base Images do not support other platforms then linux/amd64 ## And for Alpine we define all build images here, they will only be loaded when actually used -FROM --platform=linux/amd64 ghcr.io/blackdex/rust-musl:x86_64-musl-stable-1.72.1 as build_amd64 -FROM --platform=linux/amd64 ghcr.io/blackdex/rust-musl:aarch64-musl-stable-1.72.1 as build_arm64 -FROM --platform=linux/amd64 ghcr.io/blackdex/rust-musl:armv7-musleabihf-stable-1.72.1 as build_armv7 -FROM --platform=linux/amd64 ghcr.io/blackdex/rust-musl:arm-musleabi-stable-1.72.1 as build_armv6 +FROM --platform=linux/amd64 ghcr.io/blackdex/rust-musl:x86_64-musl-stable-1.73.0 as build_amd64 +FROM --platform=linux/amd64 ghcr.io/blackdex/rust-musl:aarch64-musl-stable-1.73.0 as build_arm64 +FROM --platform=linux/amd64 ghcr.io/blackdex/rust-musl:armv7-musleabihf-stable-1.73.0 as build_armv7 +FROM --platform=linux/amd64 ghcr.io/blackdex/rust-musl:arm-musleabi-stable-1.73.0 as build_armv6 ########################## BUILD IMAGE ########################## # hadolint ignore=DL3006 @@ -81,8 +81,7 @@ ARG DB=sqlite,mysql,postgresql,enable_mimalloc RUN source /env-cargo && \ rustup target add "${CARGO_TARGET}" -# ARG CARGO_PROFILE=release -ARG CARGO_PROFILE=dev +ARG CARGO_PROFILE=release # Builds your dependencies and removes the # dummy project, except the target folder diff --git a/docker/Dockerfile.debian b/docker/Dockerfile.debian index cacfff38c0b..edeec27358e 100644 --- a/docker/Dockerfile.debian +++ b/docker/Dockerfile.debian @@ -33,7 +33,7 @@ FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx:master AS xx ########################## BUILD IMAGE ########################## # hadolint ignore=DL3006 -FROM --platform=$BUILDPLATFORM docker.io/library/rust:1.72.1-slim-bookworm as build +FROM --platform=$BUILDPLATFORM docker.io/library/rust:1.73.0-slim-bookworm as build COPY --from=xx / / ARG TARGETARCH ARG TARGETVARIANT @@ -100,8 +100,7 @@ ARG DB=sqlite,mysql,postgresql RUN source /env-cargo && \ rustup target add "${CARGO_TARGET}" -# ARG CARGO_PROFILE=release -ARG CARGO_PROFILE=dev +ARG CARGO_PROFILE=release # Builds your dependencies and removes the # dummy project, except the target folder diff --git a/docker/Dockerfile.j2 b/docker/Dockerfile.j2 index 8292869d4c5..1a182116c27 100644 --- a/docker/Dockerfile.j2 +++ b/docker/Dockerfile.j2 @@ -129,8 +129,7 @@ ARG DB=sqlite,mysql,postgresql,enable_mimalloc RUN source /env-cargo && \ rustup target add "${CARGO_TARGET}" -# ARG CARGO_PROFILE=release -ARG CARGO_PROFILE=dev +ARG CARGO_PROFILE=release # Builds your dependencies and removes the # dummy project, except the target folder diff --git a/docker/README.md b/docker/README.md index daff7916b68..ad81e3b99e2 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,7 +1,121 @@ # Vaultwarden Container Building -## Local container building +To build and release new testing and stable releases of Vaultwarden we use `docker buildx bake`.
+This can be used locally by running the command your self, but it is also used by GitHub Actions. + +This makes it easier for us to test and maintain the different architectures we provide.
+We also just have two Dockerfile's one for Debian and one for Alpine based images.
+With just these two files we can build both Debian and Alpine images for the following platforms: + - amd64 (linux/amd64) + - arm64 (linux/arm64) + - armv7 (linux/arm/v7) + - armv6 (linux/arm/v6) + +To build these containers you need to enable QEMU binfmt support to be able to run/emulate architectures which are different then your host.
+This ensures the container build process can run binaries from other architectures.
+ +**NOTE**: Run all the examples below from the root of the repo.
+ + +## How to install QEMU binfmt support + +This is different per host OS, but most support this in some way.
+ +### Ubuntu/Debian +```bash +apt install binfmt-support qemu-user-static +``` + +### Arch Linux (others based upon it) +```bash +pacman -S qemu-user-static qemu-user-static-binfmt +``` + +### Fedora +```bash +dnf install qemu-user-static +``` + +### Others +There also is an option to use an other docker container to provide support for this. +```bash +# To install and activate +docker run --privileged --rm tonistiigi/binfmt --install arm64,arm +# To unistall +docker run --privileged --rm tonistiigi/binfmt --uninstall 'qemu-*' +``` + + +## Single architecture container building + +You can build a container per supported architecture as long as you have QEMU binfmt support installed on your system.
+ +```bash +# Default bake triggers a Debian build using the hosts architecture +docker buildx bake --file docker/docker-bake.hcl + +# Bake Debian ARM64 using a debug build +CARGO_PROFILE=dev \ +SOURCE_COMMIT="$(git rev-parse HEAD)" \ +docker buildx bake --file docker/docker-bake.hcl debian-arm64 + +# Bake Alpine ARMv6 as a release build +SOURCE_COMMIT="$(git rev-parse HEAD)" \ +docker buildx bake --file docker/docker-bake.hcl alpine-armv6 +``` + + +## Local Multi Architecture container building + +Start the the initialization, this only needs to be done once. + +```bash +# Create and use a new buildx builder instance which connects to the host network +docker buildx create --name vaultwarden --use --driver-opt network=host + +# Validate it runs +docker buildx inspect --bootstrap + +# Create a local container registry directly reachable on the localhost +docker run -d --name registry --network host registry:2 +``` + +After that is done, you should be able to build and push to the local registry.
+Use the following command with the modified variables to bake the Alpine images.
+Replace `alpine` with `debian` if you want to build the debian multi arch images. ```bash -docker buildx create --name multiarch --use --driver-opt network=host +# Start a buildx bake using a debug build +CARGO_PROFILE=dev \ +SOURCE_COMMIT="$(git rev-parse HEAD)" \ +CONTAINER_REGISTRIES="localhost:5000/vaultwarden/server" \ +docker buildx bake --file docker/docker-bake.hcl alpine-multi ``` + +## Using the `bake.sh` script + +To make it a bit more easier to trigger a build, there also is a `bake.sh` script.
+This script calls `docker buildx bake` with all the right parameters and also generates the `SOURCE_COMMIT` and `SOURCE_VERSION` variables.
+This script can be called from both the repo root or within the docker directory. + +So, if you want to build a Multi Arch Alpine container pushing to your localhost registry you can run this from within the docker directory. (Just make sure you executed the initialization steps above first) +```bash +CONTAINER_REGISTRIES="localhost:5000/vaultwarden/server" \ +./bake.sh alpine-multi +``` + +Or if you want to just build a Debian container from the repo root, you can run this. +```bash +docker/bake.sh +``` + +## Variables supported +| Variable | default | description | +| --------------------- | ------------------ | ----------- | +| CARGO_PROFILE | null | Which cargo profile to use. `null` means what is defined in the Dockerfile | +| DB | null | Which `features` to build. `null` means what is defined in the Dockerfile | +| SOURCE_REPOSITORY_URL | null | The source repository form where this build is triggered | +| SOURCE_COMMIT | null | The commit hash of the current commit for this build | +| SOURCE_VERSION | null | The current exact tag of this commit, else the last tag and the first 8 chars of the source commit | +| BASE_TAGS | testing | Tags to be used. Can be a comma separated value like "latest,1.29.2" | +| CONTAINER_REGISTRIES | vaultwarden/server | Comma separated value of container registries. Like `ghcr.io/dani-garcia/vaultwarden,docker.io/vaultwarden/server` | diff --git a/docker/bake.sh b/docker/bake.sh new file mode 100755 index 00000000000..fa10179d71c --- /dev/null +++ b/docker/bake.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env sh + +# Determine the basedir of this script. +# It should be located in the same directory as the docker-bake.hcl +# This ensures you can run this script from both inside and outside of the docker directory +BASEDIR=$(RL=$(readlink -n "$0"); SP="${RL:-$0}"; dirname "$(cd "$(dirname "${SP}")" || exit; pwd)/$(basename "${SP}")") + +if [ -z "${SOURCE_COMMIT}" ]; then + SOURCE_COMMIT="$(git rev-parse HEAD)" +fi + +GIT_EXACT_TAG="$(git describe --tags --abbrev=0 --exact-match 2>/dev/null)" +if [ -n "${GIT_EXACT_TAG}" ]; then + SOURCE_VERSION="${GIT_EXACT_TAG}" +else + GIT_LAST_TAG="$(git describe --tags --abbrev=0)" + SOURCE_VERSION="${GIT_LAST_TAG}-$(printf '%s' "${SOURCE_COMMIT}" | cut -c 8)" +fi + +# Export the rendered variables above so bake will use them +export SOURCE_COMMIT +export SOURCE_VERSION + +# Make sure we set the context to `..` so it will go up one directory +docker buildx bake --progress plain --set "*.context=${BASEDIR}/.." -f "${BASEDIR}/docker-bake.hcl" "$@" diff --git a/docker/docker-bake.hcl b/docker/docker-bake.hcl index b9509abae75..bc25ca590b0 100644 --- a/docker/docker-bake.hcl +++ b/docker/docker-bake.hcl @@ -1,6 +1,6 @@ // ==== Baking Variables ==== -// Set which cargo provile to use, dev or release for example +// Set which cargo profile to use, dev or release for example // Use the value provided in the Dockerfile as default variable "CARGO_PROFILE" { default = null @@ -71,6 +71,7 @@ target "_default_attributes" { // ==== Debian Baking ==== +// Default Debian target, will build a container using the hosts platform architecture target "debian" { inherits = ["_default_attributes"] dockerfile = "docker/Dockerfile.debian" @@ -78,16 +79,49 @@ target "debian" { tags = generate_tags("", platform_tag()) } -target "debian-all" { +// Multi Platform target, will build one tagged manifest with all supported architectures +// This is mainly used by GitHub Actions to build and push new containers +target "debian-multi" { inherits = ["debian"] platforms = ["linux/amd64", "linux/arm64", "linux/arm/v7", "linux/arm/v6"] tags = generate_tags("", "") output = ["type=registry"] } +// Per platform targets, to individually test building per platform locally +target "debian-amd64" { + inherits = ["debian"] + platforms = ["linux/amd64"] + tags = generate_tags("", "-amd64") +} + +target "debian-arm64" { + inherits = ["debian"] + platforms = ["linux/arm64"] + tags = generate_tags("", "-arm64") +} + +target "debian-armv7" { + inherits = ["debian"] + platforms = ["linux/arm/v7"] + tags = generate_tags("", "-armv7") +} + +target "debian-armv6" { + inherits = ["debian"] + platforms = ["linux/arm/v6"] + tags = generate_tags("", "-armv6") +} + +// A Group to build all platforms individually for local testing +group "debian-all" { + targets = ["debian-amd64", "debian-arm64", "debian-armv7", "debian-armv6"] +} + // ==== Alpine Baking ==== +// Default Alpine target, will build a container using the hosts platform architecture target "alpine" { inherits = ["_default_attributes"] dockerfile = "docker/Dockerfile.alpine" @@ -95,13 +129,52 @@ target "alpine" { tags = generate_tags("-alpine", platform_tag()) } -target "alpine-all" { +// Multi Platform target, will build one tagged manifest with all supported architectures +// This is mainly used by GitHub Actions to build and push new containers +target "alpine-multi" { inherits = ["alpine"] platforms = ["linux/amd64", "linux/arm64", "linux/arm/v7", "linux/arm/v6"] tags = generate_tags("-alpine", "") output = ["type=registry"] } +// Per platform targets, to individually test building per platform locally +target "alpine-amd64" { + inherits = ["alpine"] + platforms = ["linux/amd64"] + tags = generate_tags("-alpine", "-amd64") +} + +target "alpine-arm64" { + inherits = ["alpine"] + platforms = ["linux/arm64"] + tags = generate_tags("-alpine", "-arm64") +} + +target "alpine-armv7" { + inherits = ["alpine"] + platforms = ["linux/arm/v7"] + tags = generate_tags("-alpine", "-armv7") +} + +target "alpine-armv6" { + inherits = ["alpine"] + platforms = ["linux/arm/v6"] + tags = generate_tags("-alpine", "-armv6") +} + +// A Group to build all platforms individually for local testing +group "alpine-all" { + targets = ["alpine-amd64", "alpine-arm64", "alpine-armv7", "alpine-armv6"] +} + + +// ==== Bake everything locally ==== + +group "all" { + targets = ["debian-all", "alpine-all"] +} + // ==== Baking functions ==== diff --git a/rust-toolchain.toml b/rust-toolchain.toml index e279de73a02..b7979b7cab3 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.72.1" +channel = "1.73.0" components = [ "rustfmt", "clippy" ] profile = "minimal"