From 14218185e15148965552cc3618441f6b27c00afd Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Fri, 13 Jan 2023 22:11:30 +0800 Subject: [PATCH 1/3] refactor: add features for different mods Some dependencies are only used in a part of the lib. New features are brought for users to specify to reduce useless dependencies. Signed-off-by: Xynnn007 --- Cargo.toml | 39 ++++++++++++++++++------------------ src/cosign/client_builder.rs | 31 +++++++++++++++++++--------- src/crypto/mod.rs | 2 ++ src/errors.rs | 4 ++++ src/lib.rs | 14 +++++++++++++ src/registry/mod.rs | 4 ++++ 6 files changed, 65 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b8ad03584a..7022d76ec1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,40 +19,41 @@ test-registry = [] [dependencies] async-trait = "0.1.52" base64 = "0.21.0" -cached = "0.42.0" +cached = { version = "0.42.0", optional = true } +cfg-if = "1.0.0" +digest = "0.10.3" +ecdsa = { version = "0.14.3", features = [ "pkcs8", "digest", "der" ] } +ed25519 = { version = "1", features = [ "alloc" ] } +ed25519-dalek-fiat = "0.1.0" +elliptic-curve = { version = "0.12.2", features = [ "arithmetic", "pem" ] } lazy_static = "1.4.0" oci-distribution = { version = "0.9", default-features = false } olpc-cjson = "0.1" open = "3.0.1" openidconnect = { version = "2.3", default-features = false, features = [ "reqwest" ] } +p256 = "0.11.1" +p384 = "0.11.1" pem = "1.0.2" picky = { version = "7.0.0-rc.3", default-features = false, features = [ "x509", "ec" ] } +pkcs1 = "0.4.0" +pkcs8 = { version = "0.9.0", features = ["pem", "alloc", "pkcs5", "encryption"] } +rand = { version = "0.8.5", features = [ "getrandom", "std" ] } regex = "1.5.5" -serde_json = "1.0.79" +reqwest = { version = "0.11", default-features = false, features = ["json", "multipart"] } +rsa = "0.7.0" +scrypt = "0.10.0" serde = { version = "1.0.136", features = ["derive"] } +serde_json = "1.0.79" sha2 = { version = "0.10.6", features = ["oid"] } +signature = { version = "1.5.0", features = [ "digest-preview" ] } thiserror = "1.0.30" tokio = { version = "1.17.0", features = ["full"] } tough = { version = "0.12", features = [ "http" ] } tracing = "0.1.31" url = "2.2.2" x509-parser = { version = "0.14.0", features = ["verify"] } -zeroize = "1.5.7" -rand = { version = "0.8.5", features = [ "getrandom", "std" ] } -scrypt = "0.10.0" xsalsa20poly1305 = "0.9.0" -pkcs8 = { version = "0.9.0", features = ["pem", "alloc", "pkcs5", "encryption"] } -elliptic-curve = { version = "0.12.2", features = [ "arithmetic", "pem" ] } -p256 = "0.11.1" -p384 = "0.11.1" -ecdsa = { version = "0.14.3", features = [ "pkcs8", "digest", "der" ] } -digest = "0.10.3" -signature = { version = "1.5.0", features = [ "digest-preview" ] } -ed25519 = { version = "1", features = [ "alloc" ] } -ed25519-dalek-fiat = "0.1.0" -rsa = "0.7.0" -pkcs1 = "0.4.0" -reqwest = { version = "0.11", default-features = false, features = ["json", "multipart"] } +zeroize = "1.5.7" [dev-dependencies] anyhow = { version = "1.0", features = ["backtrace"] } @@ -62,10 +63,10 @@ clap = { version = "4.0.8", features = ["derive"] } docker_credential = "1.1.0" openssl = "0.10.38" rstest = "0.16.0" +serial_test = "1.0.0" tempfile = "3.3.0" -tracing-subscriber = { version = "0.3.9", features = ["env-filter"] } testcontainers = "0.14" -serial_test = "1.0.0" +tracing-subscriber = { version = "0.3.9", features = ["env-filter"] } # cosign example mappings diff --git a/src/cosign/client_builder.rs b/src/cosign/client_builder.rs index 6445834d80..83b58a9ad1 100644 --- a/src/cosign/client_builder.rs +++ b/src/cosign/client_builder.rs @@ -54,11 +54,13 @@ pub struct ClientBuilder { oci_client_config: ClientConfig, rekor_pub_key: Option, fulcio_certs: Vec, + #[cfg(feature = "cached-client")] enable_registry_caching: bool, } impl ClientBuilder { /// Enable caching of data returned from remote OCI registries + #[cfg(feature = "cached-client")] pub fn enable_registry_caching(mut self) -> Self { self.enable_registry_caching = true; self @@ -139,16 +141,25 @@ impl ClientBuilder { let oci_client = oci_distribution::client::Client::new(self.oci_client_config.clone().into()); - let registry_client: Box = - if self.enable_registry_caching { - Box::new(crate::registry::OciCachingClient { - registry_client: oci_client, - }) - } else { - Box::new(crate::registry::OciClient { - registry_client: oci_client, - }) - }; + let registry_client: Box = { + cfg_if::cfg_if! { + if #[cfg(feature = "cached-client")] { + if self.enable_registry_caching { + Box::new(crate::registry::OciCachingClient { + registry_client: oci_client, + }) as Box + } else { + Box::new(crate::registry::OciClient { + registry_client: oci_client, + }) as Box + } + } else { + Box::new(crate::registry::OciClient { + registry_client: oci_client, + }) as Box + } + } + }; Ok(Client { registry_client, diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index da50593809..4b89bda034 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -173,7 +173,9 @@ pub enum Signature<'a> { Base64Encoded(&'a [u8]), } +#[cfg(feature = "cert")] pub(crate) mod certificate; +#[cfg(feature = "cert")] pub(crate) mod certificate_pool; pub mod verification_key; diff --git a/src/errors.rs b/src/errors.rs index ef4ad277a2..92e689e5de 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -17,16 +17,19 @@ use thiserror::Error; +#[cfg(feature = "cosign")] use crate::cosign::{ constraint::SignConstraintRefVec, verification_constraint::VerificationConstraintRefVec, }; +#[cfg(feature = "cosign")] #[derive(Error, Debug)] #[error("Several Signature Layers failed verification")] pub struct SigstoreVerifyConstraintsError<'a> { pub unsatisfied_constraints: VerificationConstraintRefVec<'a>, } +#[cfg(feature = "cosign")] #[derive(Error, Debug)] #[error("Several Constraints failed to apply on the SignatureLayer")] pub struct SigstoreApplicationConstraintsError<'a> { @@ -142,6 +145,7 @@ pub enum SigstoreError { #[error("No Signature Layer passed verification")] SigstoreNoVerifiedLayer, + #[cfg(feature = "tuf")] #[error(transparent)] TufError(#[from] tough::error::Error), diff --git a/src/lib.rs b/src/lib.rs index b8b9061b91..2dcfb046e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -227,12 +227,26 @@ #![warn(clippy::unwrap_used, clippy::panic)] pub mod crypto; + +#[cfg(feature = "mock-client")] mod mock_client; +#[cfg(feature = "cosign")] pub mod cosign; + pub mod errors; + +#[cfg(feature = "fulcio")] pub mod fulcio; + +#[cfg(feature = "oauth")] pub mod oauth; + +#[cfg(feature = "registry")] pub mod registry; + +#[cfg(feature = "rekor")] pub mod rekor; + +#[cfg(feature = "tuf")] pub mod tuf; diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 565ab5fa59..11e8277f03 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -16,10 +16,14 @@ pub mod config; pub use config::*; +#[cfg(feature = "cosign")] pub(crate) mod oci_client; +#[cfg(feature = "cosign")] pub(crate) use oci_client::*; +#[cfg(all(feature = "cosign", feature = "cached-client"))] pub(crate) mod oci_caching_client; +#[cfg(all(feature = "cosign", feature = "cached-client"))] pub(crate) use oci_caching_client::*; use crate::errors::Result; From ccde017a19f1d644aa589de757bb52fe172d1db0 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Fri, 13 Jan 2023 22:14:42 +0800 Subject: [PATCH 2/3] docs: fix docs of examples for features To run the examples correctly, the simplest way is to enable all the features. Signed-off-by: Xynnn007 --- Cargo.toml | 46 ++++++++++++++++++++++++++------ examples/README.md | 4 +-- examples/cosign/sign/README.md | 4 ++- examples/cosign/verify/README.md | 4 ++- examples/openidflow/README.md | 2 +- src/lib.rs | 23 ++++++++++++++++ 6 files changed, 70 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7022d76ec1..48b24d5968 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,12 +10,42 @@ license = "Apache-2.0" readme = "README.md" [features] -default = ["native-tls", "test-registry"] -native-tls = ["oci-distribution/native-tls", "openidconnect/native-tls", "reqwest/native-tls"] -rustls-tls = ["oci-distribution/rustls-tls", "openidconnect/rustls-tls", "reqwest/rustls-tls"] +default = ["full-native-tls", "cached-client"] + +full-native-tls = ["fulcio-native-tls", "rekor-native-tls", "cosign-native-tls", "mock-client-native-tls"] +full-rustls-tls = ["fulcio-rustls-tls", "rekor-rustls-tls", "cosign-rustls-tls", "mock-client-rustls-tls"] + # This features is used by tests that use docker to create a registry test-registry = [] +fulcio-native-tls = [ "oauth-native-tls", "reqwest/native-tls", "fulcio" ] +fulcio-rustls-tls = [ "oauth-rustls-tls", "reqwest/rustls-tls", "fulcio" ] +fulcio = [] + +oauth-native-tls = [ "openidconnect/native-tls", "oauth" ] +oauth-rustls-tls = [ "openidconnect/rustls-tls", "oauth" ] +oauth = [] + +rekor-native-tls = [ "reqwest/native-tls", "rekor"] +rekor-rustls-tls = [ "reqwest/rustls-tls", "rekor" ] +rekor = [ "tuf" ] +tuf = [ "tough", "regex" ] + +cosign-native-tls = [ "oci-distribution/native-tls", "cert", "cosign", "registry-native-tls" ] +cosign-rustls-tls = [ "oci-distribution/rustls-tls", "cert", "cosign", "registry-rustls-tls" ] +cosign = [] +cert = [] + +registry-native-tls = [ "oci-distribution/native-tls", "registry" ] +registry-rustls-tls = [ "oci-distribution/rustls-tls", "registry" ] +registry = [] + +mock-client-native-tls = [ "oci-distribution/native-tls", "mock-client" ] +mock-client-rustls-tls = [ "oci-distribution/rustls-tls", "mock-client" ] +mock-client = [] + +cached-client = [ "cached" ] + [dependencies] async-trait = "0.1.52" base64 = "0.21.0" @@ -27,10 +57,10 @@ ed25519 = { version = "1", features = [ "alloc" ] } ed25519-dalek-fiat = "0.1.0" elliptic-curve = { version = "0.12.2", features = [ "arithmetic", "pem" ] } lazy_static = "1.4.0" -oci-distribution = { version = "0.9", default-features = false } +oci-distribution = { version = "0.9", default-features = false, optional = true } olpc-cjson = "0.1" open = "3.0.1" -openidconnect = { version = "2.3", default-features = false, features = [ "reqwest" ] } +openidconnect = { version = "2.3", default-features = false, features = [ "reqwest" ], optional = true} p256 = "0.11.1" p384 = "0.11.1" pem = "1.0.2" @@ -38,8 +68,8 @@ picky = { version = "7.0.0-rc.3", default-features = false, features = [ "x509", pkcs1 = "0.4.0" pkcs8 = { version = "0.9.0", features = ["pem", "alloc", "pkcs5", "encryption"] } rand = { version = "0.8.5", features = [ "getrandom", "std" ] } -regex = "1.5.5" -reqwest = { version = "0.11", default-features = false, features = ["json", "multipart"] } +regex = { version = "1.5.5", optional = true } +reqwest = { version = "0.11", default-features = false, features = ["json", "multipart"], optional = true} rsa = "0.7.0" scrypt = "0.10.0" serde = { version = "1.0.136", features = ["derive"] } @@ -48,7 +78,7 @@ sha2 = { version = "0.10.6", features = ["oid"] } signature = { version = "1.5.0", features = [ "digest-preview" ] } thiserror = "1.0.30" tokio = { version = "1.17.0", features = ["full"] } -tough = { version = "0.12", features = [ "http" ] } +tough = { version = "0.12", features = [ "http" ], optional = true } tracing = "0.1.31" url = "2.2.2" x509-parser = { version = "0.14.0", features = ["verify"] } diff --git a/examples/README.md b/examples/README.md index 3ce6ab36ee..63450b8973 100644 --- a/examples/README.md +++ b/examples/README.md @@ -5,11 +5,11 @@ This folder contains executable examples of the sigstore-rs library. To run any given example, simply provide the subfolder name as an argument to the `cargo run` command. ```bash -cargo run --example +cargo run --example --all-features ``` e.g. ```bash -cargo run --example create_log_entry +cargo run --example create_log_entry --all-features ``` diff --git a/examples/cosign/sign/README.md b/examples/cosign/sign/README.md index 44d5e4528e..b714424af1 100644 --- a/examples/cosign/sign/README.md +++ b/examples/cosign/sign/README.md @@ -26,7 +26,9 @@ Also, let us the annotation `a=1`. Sign a container image: ```console -cargo run --example sign -- \ +cargo run --example sign \ + --all-features \ + -- \ --key cosign.key \ --image 172.17.0.2:5000/ubuntu \ --signing-scheme ECDSA_P256_SHA256_ASN1 \ diff --git a/examples/cosign/verify/README.md b/examples/cosign/verify/README.md index 372729df3d..ba25dad5ea 100644 --- a/examples/cosign/verify/README.md +++ b/examples/cosign/verify/README.md @@ -24,7 +24,9 @@ Verify the image signature using the example program defined in [main.rs](./main.rs): ```console -cargo run --example verify -- \ +cargo run --example verify \ + --all-features \ + -- \ -k cosign.pub \ --rekor-pub-key ~/.sigstore/root/targets/rekor.pub \ --fulcio-cert ~/.sigstore/root/targets/fulcio.crt.pem \ diff --git a/examples/openidflow/README.md b/examples/openidflow/README.md index 9a4cf52000..8ed9fd5b29 100644 --- a/examples/openidflow/README.md +++ b/examples/openidflow/README.md @@ -7,7 +7,7 @@ The general idea is to return an access_token and the email via a scope. Both values can then be made to form a POST request to fulcio for a software signing certificate -`cargo run --example openidconnect` +`cargo run --example openidconnect --all-features` The implementation contains a `redirect_listener` function that will create a local listening server to incept the ID token and scopes returned from diff --git a/src/lib.rs b/src/lib.rs index 2dcfb046e1..9f7f01b421 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -222,6 +222,29 @@ //! The [`sigstore::tuf`](crate::tuf) module provides the helper structures to deal //! with it. //! +//! # Feature Flags +//! +//! Sigstore-rs uses a set of [feature flags] to reduce the amount of compiled code. +//! It is suggested to just enable those features in need. The features includes: +//! +//! - `default`: Enables `full-native-tls`, `cached-client` and `test-registry` features. +//! - `full-native-tls`: Enables support for `fulcio`, `rekor` and `cosign`. All the underlying +//! tls uses `native-tls`. This feature will not enable `test-registry.` +//! - `full-rustls-tls`: Enables support for `fulcio`, `rekor` and `cosign`. All the underlying +//! tls uses `rustls-tls`. This feature will not enable `test-registry.` +//! +//! - `fulcio-native-tls` and `fulcio-rustls-tls`: Enables support for `fulcio`, but one uses +//! `native-tls` as underlying tls and the other uses `rustls-tls`. +//! +//! - `rekor-native-tls` and `rekor-rustls-tls`: Enables support for `rekor`, but one uses +//! `native-tls` as underlying tls and the other uses `rustls-tls`. +//! +//! - `cosign-native-tls` and `cosign-rustls-tls`: Enables support for `cosign`, but one uses +//! `native-tls` as underlying tls and the other uses `rustls-tls`. +//! +//! - `cached-client`: Enables support for OCI registry client caching. +//! +//! - `test-registry`: Enables tests based on a temporary OCI registry. #![forbid(unsafe_code)] #![warn(clippy::unwrap_used, clippy::panic)] From a84bbddf7668c6a44c7116dfe4eb60ef6e79a1f5 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Tue, 7 Feb 2023 10:20:13 +0800 Subject: [PATCH 3/3] ci: test for all features Signed-off-by: Xynnn007 --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f31c5127e1..f01a4552ba 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,7 +30,7 @@ jobs: - uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1.0.3 with: command: test - args: --workspace + args: --workspace --features full-native-tls,test-registry fmt: name: Rustfmt