Skip to content

Commit

Permalink
Merge pull request #392 from Xynnn007/feat-proxy
Browse files Browse the repository at this point in the history
Cosign | Add support for client to configure a proxy to pull signatures
  • Loading branch information
flavio authored Oct 15, 2024
2 parents e536360 + ef4f2e3 commit 0c61dd5
Show file tree
Hide file tree
Showing 16 changed files with 187 additions and 174 deletions.
14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,26 +67,26 @@ sigstore-trust-root-rustls-tls = [
]

cosign-native-tls = [
"oci-distribution/native-tls",
"oci-client/native-tls",
"cert",
"cosign",
"registry-native-tls",
]
cosign-rustls-tls = [
"oci-distribution/rustls-tls",
"oci-client/rustls-tls",
"cert",
"cosign",
"registry-rustls-tls",
]
cosign = ["olpc-cjson"]
cert = []

registry-native-tls = ["oci-distribution/native-tls", "registry"]
registry-rustls-tls = ["oci-distribution/rustls-tls", "registry"]
registry-native-tls = ["oci-client/native-tls", "registry"]
registry-rustls-tls = ["oci-client/rustls-tls", "registry"]
registry = ["olpc-cjson"]

mock-client-native-tls = ["oci-distribution/native-tls", "mock-client"]
mock-client-rustls-tls = ["oci-distribution/rustls-tls", "mock-client"]
mock-client-native-tls = ["oci-client/native-tls", "mock-client"]
mock-client-rustls-tls = ["oci-client/rustls-tls", "mock-client"]
mock-client = []

cached-client = ["cached"]
Expand All @@ -109,7 +109,7 @@ elliptic-curve = { version = "0.13", features = ["arithmetic", "pem"] }
futures = "0.3"
futures-util = { version = "0.3", optional = true }
lazy_static = "1.5"
oci-distribution = { version = "0.11", default-features = false, optional = true }
oci-client = { default-features = false, optional = true, version = "0.13" }
olpc-cjson = { version = "0.1", optional = true }
openidconnect = { version = "3.5", default-features = false, features = [
"reqwest",
Expand Down
5 changes: 2 additions & 3 deletions examples/cosign/verify/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,14 @@ use sigstore::errors::SigstoreVerifyConstraintsError;
use sigstore::registry::{ClientConfig, ClientProtocol, OciReference};
use sigstore::trust::sigstore::SigstoreTrustRoot;
use std::time::Instant;
use std::{collections::BTreeMap, fs};

extern crate anyhow;
use anyhow::{anyhow, Result};

extern crate clap;
use clap::Parser;

use std::{collections::HashMap, fs};

extern crate tracing_subscriber;
use tracing::{info, warn};
use tracing_subscriber::prelude::*;
Expand Down Expand Up @@ -203,7 +202,7 @@ async fn run_app(
}

if !cli.annotations.is_empty() {
let mut values: HashMap<String, String> = HashMap::new();
let mut values: BTreeMap<String, String> = BTreeMap::new();
for annotation in &cli.annotations {
let tmp: Vec<_> = annotation.splitn(2, '=').collect();
if tmp.len() == 2 {
Expand Down
27 changes: 13 additions & 14 deletions src/cosign/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;
use std::collections::BTreeMap;
use std::ops::Add;

use async_trait::async_trait;
use oci_distribution::manifest::OCI_IMAGE_MEDIA_TYPE;
use oci_client::manifest::OCI_IMAGE_MEDIA_TYPE;
use tracing::warn;

use super::constants::{SIGSTORE_OCI_MEDIA_TYPE, SIGSTORE_SIGNATURE_ANNOTATION};
Expand Down Expand Up @@ -73,8 +73,8 @@ impl CosignCapabilities for Client {
) -> Result<Vec<SignatureLayer>> {
let (manifest, layers) = self.fetch_manifest_and_layers(auth, cosign_image).await?;
let image_manifest = match manifest {
oci_distribution::manifest::OciManifest::Image(im) => im,
oci_distribution::manifest::OciManifest::ImageIndex(_) => {
oci_client::manifest::OciManifest::Image(im) => im,
oci_client::manifest::OciManifest::ImageIndex(_) => {
return Err(SigstoreError::RegistryPullManifestError {
image: cosign_image.to_string(),
error: "Found a OciImageIndex instead of a OciImageManifest".to_string(),
Expand All @@ -96,21 +96,21 @@ impl CosignCapabilities for Client {

async fn push_signature(
&mut self,
annotations: Option<HashMap<String, String>>,
annotations: Option<BTreeMap<String, String>>,
auth: &Auth,
target_reference: &OciReference,
signature_layers: Vec<SignatureLayer>,
) -> Result<PushResponse> {
let layers: Vec<oci_distribution::client::ImageLayer> = signature_layers
let layers: Vec<oci_client::client::ImageLayer> = signature_layers
.iter()
.filter_map(|sl| {
match serde_json::to_vec(&sl.simple_signing) {
Ok(data) => {
let annotations = match &sl.signature {
Some(sig) => [(SIGSTORE_SIGNATURE_ANNOTATION.into(), sig.clone())].into(),
None => HashMap::new(),
None => BTreeMap::new(),
};
let image_layer = oci_distribution::client::ImageLayer::new(data, SIGSTORE_OCI_MEDIA_TYPE.into(), Some(annotations));
let image_layer = oci_client::client::ImageLayer::new(data, SIGSTORE_OCI_MEDIA_TYPE.into(), Some(annotations));
Some(image_layer)
}
Err(e) => {
Expand All @@ -122,10 +122,9 @@ impl CosignCapabilities for Client {
.collect();

// TODO: Do we need to support OCI Image Configuration?
let config =
oci_distribution::client::Config::oci_v1(CONFIG_DATA.as_bytes().to_vec(), None);
let config = oci_client::client::Config::oci_v1(CONFIG_DATA.as_bytes().to_vec(), None);
let mut manifest =
oci_distribution::manifest::OciImageManifest::build(&layers[..], &config, annotations);
oci_client::manifest::OciImageManifest::build(&layers[..], &config, annotations);
manifest.media_type = Some(OCI_IMAGE_MEDIA_TYPE.to_string());
self.registry_client
.push(
Expand All @@ -147,10 +146,10 @@ impl Client {
auth: &Auth,
cosign_image: &OciReference,
) -> Result<(
oci_distribution::manifest::OciManifest,
Vec<oci_distribution::client::ImageLayer>,
oci_client::manifest::OciManifest,
Vec<oci_client::client::ImageLayer>,
)> {
let oci_auth: oci_distribution::secrets::RegistryAuth = auth.into();
let oci_auth: oci_client::secrets::RegistryAuth = auth.into();

let (manifest, _) = self
.registry_client
Expand Down
3 changes: 1 addition & 2 deletions src/cosign/client_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@ impl<'a> ClientBuilder<'a> {
Some(cert_pool)
};

let oci_client =
oci_distribution::client::Client::new(self.oci_client_config.clone().into());
let oci_client = oci_client::client::Client::new(self.oci_client_config.clone().into());

let registry_client: Box<dyn crate::registry::ClientCapabilities> = {
cfg_if::cfg_if! {
Expand Down
4 changes: 2 additions & 2 deletions src/cosign/constraint/annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};

use serde_json::Value;
use tracing::warn;
Expand Down Expand Up @@ -50,7 +50,7 @@ impl Constraint for AnnotationMarker {
warn!(optional = ?opt, "already has an annotation field");
opt.extra.clone()
}
None => HashMap::new(),
None => BTreeMap::new(),
};

for (k, v) in &self.annotations {
Expand Down
22 changes: 11 additions & 11 deletions src/cosign/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
//! In case you want to mock sigstore interactions inside of your own code, you
//! can implement the [`CosignCapabilities`] trait inside of your test suite.

use std::collections::HashMap;
use std::collections::BTreeMap;

use async_trait::async_trait;
use tracing::warn;
Expand Down Expand Up @@ -126,9 +126,9 @@ pub trait CosignCapabilities {

/// Push [`SignatureLayer`] objects to the registry. This function will do
/// the following steps:
/// * Generate a series of [`oci_distribution::client::ImageLayer`]s due to
/// * Generate a series of [`oci_client::client::ImageLayer`]s due to
/// the given [`Vec<SignatureLayer>`].
/// * Generate a `OciImageManifest` of [`oci_distribution::manifest::OciManifest`]
/// * Generate a `OciImageManifest` of [`oci_client::manifest::OciManifest`]
/// due to the given `source_image_digest` and `signature_layers`. It supports
/// to be extended when newly published
/// [Referrers API of OCI Registry v1.1.0](https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#listing-referrers),
Expand All @@ -146,7 +146,7 @@ pub trait CosignCapabilities {
/// - `signature_layers`: [`SignatureLayer`] objects containing signature information
async fn push_signature(
&mut self,
annotations: Option<HashMap<String, String>>,
annotations: Option<BTreeMap<String, String>>,
auth: &Auth,
target_reference: &OciReference,
signature_layers: Vec<SignatureLayer>,
Expand Down Expand Up @@ -357,7 +357,7 @@ TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ
let email = "[email protected]".to_string();
let issuer = "an issuer".to_string();

let mut annotations: HashMap<String, String> = HashMap::new();
let mut annotations: BTreeMap<String, String> = BTreeMap::new();
annotations.insert("key1".into(), "value1".into());
annotations.insert("key2".into(), "value2".into());

Expand All @@ -370,7 +370,7 @@ TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ
cert_signature.subject = cert_subj;
sl.certificate_signature = Some(cert_signature);

let mut extra: HashMap<String, serde_json::Value> = annotations
let mut extra: BTreeMap<String, serde_json::Value> = annotations
.iter()
.map(|(k, v)| (k.clone(), json!(v)))
.collect();
Expand Down Expand Up @@ -422,7 +422,7 @@ TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ
cert_signature.subject = cert_subj;
sl.certificate_signature = Some(cert_signature);

let mut extra: HashMap<String, serde_json::Value> = HashMap::new();
let mut extra: BTreeMap<String, serde_json::Value> = BTreeMap::new();
extra.insert("something extra".into(), json!("value extra"));

let mut simple_signing = sl.simple_signing;
Expand Down Expand Up @@ -470,7 +470,7 @@ TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ
cert_signature.subject = cert_subj;
sl.certificate_signature = Some(cert_signature);

let mut extra: HashMap<String, serde_json::Value> = HashMap::new();
let mut extra: BTreeMap<String, serde_json::Value> = BTreeMap::new();
extra.insert("something extra".into(), json!("value extra"));

let mut simple_signing = sl.simple_signing;
Expand Down Expand Up @@ -652,8 +652,8 @@ TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ
.registry_client
.pull(
&SIGNED_IMAGE.parse().expect("failed to parse image ref"),
&oci_distribution::secrets::RegistryAuth::Anonymous,
vec![oci_distribution::manifest::IMAGE_DOCKER_LAYER_GZIP_MEDIA_TYPE],
&oci_client::secrets::RegistryAuth::Anonymous,
vec![oci_client::manifest::IMAGE_DOCKER_LAYER_GZIP_MEDIA_TYPE],
)
.await
.expect("pull test image failed");
Expand All @@ -664,7 +664,7 @@ TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ
&image_ref.oci_reference,
&data.layers[..],
data.config.clone(),
&oci_distribution::secrets::RegistryAuth::Anonymous,
&oci_client::secrets::RegistryAuth::Anonymous,
None,
)
.await
Expand Down
20 changes: 10 additions & 10 deletions src/cosign/payload/simple_signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::registry::OciReference;

use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::{collections::HashMap, fmt};
use std::{collections::BTreeMap, fmt};
use tracing::{debug, error, info};

/// Default type name of [`Critical`] when doing cosign signing
Expand Down Expand Up @@ -65,7 +65,7 @@ impl SimpleSigning {
}

/// Checks whether all the provided `annotations` are satisfied
pub fn satisfies_annotations(&self, annotations: &HashMap<String, String>) -> bool {
pub fn satisfies_annotations(&self, annotations: &BTreeMap<String, String>) -> bool {
if annotations.is_empty() {
debug!("no annotations have been provided -> returning true");
return true;
Expand Down Expand Up @@ -128,12 +128,12 @@ pub struct Optional {
pub timestamp: Option<i64>,

#[serde(flatten)]
pub extra: HashMap<String, Value>,
pub extra: BTreeMap<String, Value>,
}

impl Optional {
/// Checks whether all the provided `annotations` are satisfied
pub fn satisfies_annotations(&self, annotations: &HashMap<String, String>) -> bool {
pub fn satisfies_annotations(&self, annotations: &BTreeMap<String, String>) -> bool {
if self.extra.is_empty() {
info!(?annotations, "Annotations are not satisfied, no annotations are part of the Simple Signing object");
return false;
Expand Down Expand Up @@ -221,7 +221,7 @@ mod tests {
});
let ss: SimpleSigning = serde_json::from_value(ss_json).unwrap();

let mut annotations: HashMap<String, String> = HashMap::new();
let mut annotations: BTreeMap<String, String> = BTreeMap::new();
annotations.insert(String::from("env"), String::from("prod"));

assert!(!ss.satisfies_annotations(&annotations));
Expand All @@ -241,14 +241,14 @@ mod tests {
}
});
let ss: SimpleSigning = serde_json::from_value(ss_json).unwrap();
let annotations: HashMap<String, String> = HashMap::new();
let annotations: BTreeMap<String, String> = BTreeMap::new();

assert!(ss.satisfies_annotations(&annotations));
}

#[test]
fn optional_has_all_the_required_annotations() {
let mut annotations: HashMap<String, String> = HashMap::new();
let mut annotations: BTreeMap<String, String> = BTreeMap::new();
annotations.insert(String::from("env"), String::from("prod"));
annotations.insert(String::from("number"), String::from("1"));
annotations.insert(String::from("bool"), String::from("true"));
Expand All @@ -265,7 +265,7 @@ mod tests {

#[test]
fn optional_does_not_satisfy_annotations_because_one_annotation_is_missing() {
let mut annotations: HashMap<String, String> = HashMap::new();
let mut annotations: BTreeMap<String, String> = BTreeMap::new();
annotations.insert(String::from("env"), String::from("prod"));
annotations.insert(String::from("owner"), String::from("flavio"));

Expand All @@ -280,7 +280,7 @@ mod tests {

#[test]
fn optional_does_not_satisfy_annotations_because_one_annotation_has_different_value() {
let mut annotations: HashMap<String, String> = HashMap::new();
let mut annotations: BTreeMap<String, String> = BTreeMap::new();
annotations.insert(String::from("env"), String::from("prod"));
annotations.insert(String::from("owner"), String::from("flavio"));

Expand All @@ -296,7 +296,7 @@ mod tests {

#[test]
fn optional_satisfies_annotations_when_no_annotation_is_provided() {
let annotations: HashMap<String, String> = HashMap::new();
let annotations: BTreeMap<String, String> = BTreeMap::new();

let optional_json = json!({
"env": "prod",
Expand Down
Loading

0 comments on commit 0c61dd5

Please sign in to comment.