Skip to content

Commit

Permalink
Merge pull request containers#202 from cgwalters/add-digest-type
Browse files Browse the repository at this point in the history
Add Digest and SHA256Digest
  • Loading branch information
cgwalters committed Aug 30, 2024
2 parents 57570dd + 5601907 commit d3ddc0b
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 25 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,42 +37,44 @@ assert_eq!(image_manifest.layers().len(), 5);

- Create new image manifest using builder
```rust no_run
use std::str::FromStr;
use oci_spec::image::{
Descriptor,
DescriptorBuilder,
ImageManifest,
ImageManifestBuilder,
MediaType,
Sha256Digest,
SCHEMA_VERSION
};

let config = DescriptorBuilder::default()
.media_type(MediaType::ImageConfig)
.size(7023u64)
.digest("sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7")
.digest(Sha256Digest::from_str("b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7").unwrap())
.build()
.expect("build config descriptor");

let layers: Vec<Descriptor> = [
(
32654u64,
"sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0",
"9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0",
),
(
16724,
"sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b",
"3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b",
),
(
73109,
"sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736",
"ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736",
),
]
.iter()
.map(|l| {
DescriptorBuilder::default()
.media_type(MediaType::ImageLayerGzip)
.size(l.0)
.digest(l.1.to_owned())
.digest(Sha256Digest::from_str(l.1).unwrap())
.build()
.expect("build layer")
})
Expand Down
16 changes: 10 additions & 6 deletions src/image/artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@ impl ArtifactManifest {
#[cfg(test)]
mod tests {
use super::*;
use crate::image::DescriptorBuilder;
use std::path::PathBuf;
use crate::image::{DescriptorBuilder, Sha256Digest};
use std::{path::PathBuf, str::FromStr};

fn get_manifest_path() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/data/artifact_manifest.json")
Expand All @@ -228,17 +228,21 @@ mod tests {
.media_type(MediaType::Other("application/gzip".to_string()))
.size(123u64)
.digest(
"sha256:87923725d74f4bfb94c9e86d64170f7521aad8221a5de834851470ca142da630"
.to_string(),
Sha256Digest::from_str(
"87923725d74f4bfb94c9e86d64170f7521aad8221a5de834851470ca142da630",
)
.unwrap(),
)
.build()
.unwrap();
let subject = DescriptorBuilder::default()
.media_type(MediaType::ImageManifest)
.size(1234u64)
.digest(
"sha256:cc06a2839488b8bd2a2b99dcdc03d5cfd818eed72ad08ef3cc197aac64c0d0a0"
.to_string(),
Sha256Digest::from_str(
"cc06a2839488b8bd2a2b99dcdc03d5cfd818eed72ad08ef3cc197aac64c0d0a0",
)
.unwrap(),
)
.build()
.unwrap();
Expand Down
29 changes: 25 additions & 4 deletions src/image/descriptor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Arch, MediaType, Os};
use super::{Arch, Digest, MediaType, Os};
use crate::error::OciSpecError;
use derive_builder::Builder;
use getset::{CopyGetters, Getters, Setters};
Expand Down Expand Up @@ -30,7 +30,7 @@ pub struct Descriptor {
/// content SHOULD be verified against this digest when consumed via
/// untrusted sources.
#[getset(get = "pub", set = "pub")]
digest: String,
digest: Digest,
/// This REQUIRED property specifies the size, in bytes, of the raw
/// content. This property exists so that a client will have an
/// expected size for the content before processing. If the
Expand Down Expand Up @@ -133,7 +133,7 @@ pub struct Platform {

impl Descriptor {
/// Construct a new descriptor with the required fields.
pub fn new(media_type: MediaType, size: u64, digest: impl Into<String>) -> Self {
pub fn new(media_type: MediaType, size: u64, digest: impl Into<Digest>) -> Self {
Self {
media_type,
size,
Expand All @@ -145,10 +145,17 @@ impl Descriptor {
data: Default::default(),
}
}

/// Return a view of [`Self::digest()`] that has been parsed as a valid SHA-256 digest.
pub fn digest_sha256(&self) -> crate::Result<super::Sha256Digest> {
super::Sha256Digest::try_from(self.digest().clone())
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr;

use super::*;

#[test]
Expand All @@ -163,7 +170,10 @@ mod tests {
assert_eq!(descriptor.media_type, MediaType::ImageManifest);
assert_eq!(
descriptor.digest,
"sha256:c2b8beca588702777e5f35dafdbeae9ec16c2bab802331f81cacd2a92f1d5356"
Digest::from_str(
"sha256:c2b8beca588702777e5f35dafdbeae9ec16c2bab802331f81cacd2a92f1d5356"
)
.unwrap()
);
assert_eq!(descriptor.size, 769);
assert_eq!(
Expand All @@ -178,4 +188,15 @@ mod tests {
MediaType::Other("application/spdx+json".to_string())
);
}

#[test]
fn test_malformed_digest() {
let descriptor_str = r#"{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest":"../blah:this-is-an-attack",
"size":769,
"annotations":{"org.opencontainers.image.created": "2023-10-11T22:37:26Z"},
"artifactType":"application/spdx+json"}"#;
assert!(serde_json::from_str::<Descriptor>(descriptor_str).is_err());
}
}
Loading

0 comments on commit d3ddc0b

Please sign in to comment.