1
0
Fork 0
mirror of https://github.com/imjasonh/krust synced 2026-07-08 06:45:32 +00:00

feat: Fork oci-distribution and add enhanced features

- Fork oci-distribution v0.11.0 into vendor/oci-distribution
- Add get_image_platforms() method for proper platform detection
- Support fetching config blobs for single-platform images
- Add OAuth2/Bearer token authentication support
- Add push_manifest_and_get_digest() for reliable digest extraction
- Update krust to use the forked version with enhanced features
This commit is contained in:
Jason Hall 2025-06-08 09:49:41 -04:00
parent e2c4b6b14c
commit 7827c25d9b
Failed to extract signature
4 changed files with 84 additions and 83 deletions

View file

@ -19,7 +19,7 @@ sha256 = "1.5"
chrono = "0.4"
tar = "0.4"
flate2 = "1.0"
oci-distribution = "0.11"
oci-distribution = { path = "vendor/oci-distribution" }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
dirs = "6.0"

View file

@ -83,6 +83,16 @@ impl AuthConfig {
return RegistryAuth::Anonymous;
}
// Check for bearer tokens first
if let Some(token) = &self.registry_token {
return RegistryAuth::Bearer(token.clone());
}
if let Some(token) = &self.identity_token {
return RegistryAuth::Bearer(token.clone());
}
// Then check for basic auth
if let (Some(username), Some(password)) = (&self.username, &self.password) {
return RegistryAuth::Basic(username.clone(), password.clone());
}
@ -234,4 +244,30 @@ mod unit_tests {
let header = auth.to_authorization_header().unwrap().unwrap();
assert_eq!(header, "Bearer token123");
}
#[test]
fn test_auth_config_to_registry_auth() {
use oci_distribution::secrets::RegistryAuth;
// Test anonymous
let auth = AuthConfig::anonymous();
assert_eq!(auth.to_registry_auth(), RegistryAuth::Anonymous);
// Test basic auth
let auth = AuthConfig::new("user".to_string(), "pass".to_string());
assert_eq!(
auth.to_registry_auth(),
RegistryAuth::Basic("user".to_string(), "pass".to_string())
);
// Test bearer token
let auth = AuthConfig {
registry_token: Some("token123".to_string()),
..Default::default()
};
assert_eq!(
auth.to_registry_auth(),
RegistryAuth::Bearer("token123".to_string())
);
}
}

View file

@ -86,21 +86,14 @@ impl RegistryClient {
let manifest = OciManifest::Image(image_manifest);
debug!("Pushing manifest");
let manifest_url = self
let (manifest_url, digest) = self
.client
.push_manifest(&reference, &manifest)
.push_manifest_and_get_digest(&reference, &manifest)
.await
.context("Failed to push manifest")?;
info!("Successfully pushed image to {}", manifest_url);
// Extract digest from the manifest URL
// URL format: https://registry/v2/repo/manifests/sha256:digest
let digest = manifest_url
.split('/')
.next_back()
.context("Failed to extract digest from manifest URL")?;
// Build the full image reference with digest
let registry = reference.registry();
let repository = reference.repository();
@ -169,20 +162,14 @@ impl RegistryClient {
m.platform.os, m.platform.architecture, m.digest
);
}
let manifest_url = self
let (manifest_url, digest) = self
.client
.push_manifest(&reference, &manifest)
.push_manifest_and_get_digest(&reference, &manifest)
.await
.context("Failed to push manifest list")?;
info!("Successfully pushed manifest list to {}", manifest_url);
// Extract digest from the manifest URL
let digest = manifest_url
.split('/')
.next_back()
.context("Failed to extract digest from manifest URL")?;
// Build the full image reference with digest
let registry = reference.registry();
let repository = reference.repository();
@ -201,78 +188,55 @@ impl RegistryClient {
.parse()
.context("Failed to parse image reference")?;
debug!("Fetching manifest for {}", reference);
debug!("Fetching platforms for {}", reference);
// Pull the manifest
let (manifest, _) = self
// Use the new get_image_platforms method from oci-distribution
let platforms = self
.client
.pull_manifest(&reference, auth)
.get_image_platforms(&reference, auth)
.await
.context("Failed to pull manifest")?;
.context("Failed to get image platforms")?;
// Parse platforms based on manifest type
match manifest {
OciManifest::Image(_) => {
// Single platform image - we need to fetch the config to determine platform
debug!("Single platform image detected");
// For now, we'll assume it's linux/amd64 if we can't determine
// In a real implementation, we'd fetch the config blob
Ok(vec!["linux/amd64".to_string()])
}
OciManifest::ImageIndex(index) => {
// Multi-platform image - extract platforms from index
debug!(
"Multi-platform image detected with {} manifests",
index.manifests.len()
);
let mut platforms: Vec<String> = index
.manifests
.iter()
.filter_map(|m| {
m.platform.as_ref().and_then(|p| {
// Filter out invalid platforms
if p.os == "unknown"
|| p.architecture == "unknown"
|| p.os.is_empty()
|| p.architecture.is_empty()
{
return None;
}
// Convert (os, arch) tuples to platform strings and normalize
let mut platform_strings: Vec<String> = platforms
.into_iter()
.filter_map(|(os, arch)| {
// Filter out unknown/invalid platforms
if os == "unknown" || arch == "unknown" || os.is_empty() || arch.is_empty() {
return None;
}
let mut platform = format!("{}/{}", p.os, p.architecture);
if let Some(variant) = &p.variant {
if !variant.is_empty() {
platform.push('/');
platform.push_str(variant);
}
}
// Normalize and filter platforms
let normalized = match platform.as_str() {
"linux/amd64" => Some("linux/amd64".to_string()),
"linux/arm64" | "linux/arm64/v8" => Some("linux/arm64".to_string()),
"linux/arm/v7" => Some("linux/arm/v7".to_string()),
"linux/arm/v6" => Some("linux/arm/v6".to_string()),
"linux/386" => Some("linux/386".to_string()),
"linux/ppc64le" => Some("linux/ppc64le".to_string()),
"linux/s390x" => Some("linux/s390x".to_string()),
"linux/riscv64" => Some("linux/riscv64".to_string()),
_ => {
debug!("Skipping unsupported platform: {}", platform);
None
}
};
normalized
})
})
.collect();
let platform = format!("{}/{}", os, arch);
// Deduplicate platforms
platforms.sort();
platforms.dedup();
// Normalize and filter platforms
let normalized = match platform.as_str() {
"linux/amd64" => Some("linux/amd64".to_string()),
"linux/arm64" | "linux/arm64/v8" => Some("linux/arm64".to_string()),
"linux/arm/v7" => Some("linux/arm/v7".to_string()),
"linux/arm/v6" => Some("linux/arm/v6".to_string()),
"linux/386" => Some("linux/386".to_string()),
"linux/ppc64le" => Some("linux/ppc64le".to_string()),
"linux/s390x" => Some("linux/s390x".to_string()),
"linux/riscv64" => Some("linux/riscv64".to_string()),
_ => {
debug!("Skipping unsupported platform: {}", platform);
None
}
};
normalized
})
.collect();
info!("Found platforms: {:?}", platforms);
Ok(platforms)
}
// Deduplicate platforms
platform_strings.sort();
platform_strings.dedup();
if platform_strings.is_empty() {
debug!("No valid platforms found, defaulting to linux/amd64");
Ok(vec!["linux/amd64".to_string()])
} else {
info!("Found platforms: {:?}", platform_strings);
Ok(platform_strings)
}
}
}

1
vendor/oci-distribution vendored Submodule

@ -0,0 +1 @@
Subproject commit 6157eb998456bdd88b0a8a085a7bf70ecab6189d