### Example Usage of image() and image_for_skopeo() Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/transport.md Demonstrates how to use the image() and image_for_skopeo() methods on a ContainersStorageRef. Shows the difference in output when a 'sha256:' prefix is present. ```rust let imgref: ImageReference = "containers-storage:sha256:abc123".try_into()?; let csref = imgref.as_containers_storage().unwrap(); assert_eq!(csref.image(), "sha256:abc123"); assert_eq!(csref.image_for_skopeo(), "abc123"); ``` -------------------------------- ### Using ImageProxy to Fetch Image Manifest Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/types.md Demonstrates how to initialize `ImageProxy`, open an image, and fetch its manifest using OCI specification types. This example requires an active async runtime. ```rust use containers_image_proxy::{ImageProxy, oci_spec}; let proxy = ImageProxy::new().await?; let img = proxy.open_image("docker://...").await?; let (digest_str, manifest): (String, oci_spec::image::ImageManifest) = proxy.fetch_manifest(&img).await?; for layer in manifest.layers() { let digest: &oci_spec::image::Digest = layer.digest(); println!("Layer: {}", digest); } ``` -------------------------------- ### BlobStream Simplest Usage Example Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/types.md Shows the simplest way to use BlobStream by joining the copy operation and driver future. ```rust let stream = proxy.get_blob_stream(&img, &digest, size).await?; let (mut reader, driver) = stream.into_parts(); let copier = tokio::io::copy(&mut reader, &mut output_file); let (bytes_copied, ()) = tokio::join!(copier, driver); println!("Copied {} bytes via {:?}", bytes_copied?, stream.source()); ``` -------------------------------- ### Handle Skopeo Spawn Errors Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/errors.md Example for handling `Error::SkopeoSpawnError`, including a check for `ErrorKind::NotFound` to detect if skopeo is not installed. ```rust match ImageProxy::new().await { Err(Error::SkopeoSpawnError(e)) if e.kind() == std::io::ErrorKind::NotFound => { eprintln!("skopeo not installed or not in PATH"); } Err(Error::SkopeoSpawnError(e)) => eprintln!("Failed to spawn skopeo: {}", e), _ => {} } ``` -------------------------------- ### Complete Workflow with ImageProxy Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/transport.md Demonstrates parsing image references from strings, constructing them programmatically, and using them with the `ImageProxy` to open images and fetch manifests. Includes an example of converting to and normalizing a containers-storage reference. ```rust use containers_image_proxy::{ImageReference, Transport, ImageProxy}; // Parse reference from string let imgref: ImageReference = "docker://quay.io/fedora/fedora:latest".parse()?; assert_eq!(imgref.transport, Transport::Registry); // Or construct programmatically let imgref = ImageReference::new(Transport::Registry, "quay.io/fedora/fedora:latest"); // Use with proxy let proxy = ImageProxy::new().await?; let img = proxy.open_image_ref(&imgref).await?; let (digest, manifest) = proxy.fetch_manifest(&img).await?; // For container storage with normalization let imgref: ImageReference = "containers-storage:[store]sha256:abc123".parse()?; let csref = imgref.as_containers_storage().unwrap(); let normalized = csref.to_image_reference(true); // strips sha256: ``` -------------------------------- ### Example Usage of to_image_reference() with Normalization Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/transport.md Illustrates converting a ContainersStorageRef to an ImageReference with skopeo normalization enabled. Shows how the 'sha256:' prefix is removed. ```rust let imgref: ImageReference = "containers-storage:[overlay@/tmp]sha256:abc123".try_into()?; let csref = imgref.as_containers_storage().unwrap(); let normalized = csref.to_image_reference(true); assert_eq!(normalized.name, "[overlay@/tmp]abc123"); ``` -------------------------------- ### Complete Image Proxy Configuration Setup Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/configuration.md Use this snippet to configure the image proxy with authentication file, certificate directory, TLS verification, signature verification, decryption keys, and user agent prefix. Explicitly setting boolean options to false ensures verification. ```rust use std::path::PathBuf; let mut config = ImageProxyConfig::default(); config.authfile = Some(PathBuf::from("/etc/containers/auth.json")); config.certificate_directory = Some(PathBuf::from("/etc/containers/certs.d")); config.insecure_skip_tls_verification = Some(false); // explicit: verify TLS config.insecure_policy = Some(false); // explicit: verify signatures config.decryption_keys = Some(vec!["/etc/secrets/decrypt.key".to_string()]); config.user_agent_prefix = Some("bootc/1.0".to_string()); config.debug = true; let proxy = ImageProxy::new_with_config(config).await?; ``` -------------------------------- ### Handle Configuration Error Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/errors.md This example shows how to catch and report a `Configuration` error, which arises from invalid or conflicting configuration options. It prints the specific error message provided by the configuration. ```rust let mut config = ImageProxyConfig::default(); config.authfile = Some(PathBuf::from("/path")); config.auth_anonymous = true; // Conflict! match ImageProxy::new_with_config(config).await { Err(Error::Configuration(msg)) => { eprintln!("Configuration error: {}", msg); } _ => {} } ``` -------------------------------- ### Create ImageProxy with Default Configuration Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Use `ImageProxy::new()` to create an instance with default settings. This method automatically spawns a skopeo subprocess and negotiates the protocol version. It returns an error if the skopeo binary is not found or if the installed skopeo version is below the minimum requirement (0.2.3). ```rust let proxy = ImageProxy::new().await?; ``` -------------------------------- ### BlobStreamSource Enum Usage Example Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/types.md Demonstrates how to use the BlobStreamSource enum to determine the blob fetching method. ```rust let stream = proxy.get_blob_stream(&img, &digest, size).await?; match stream.source() { BlobStreamSource::GetRawBlob => println!("Using optimized raw blob path"), BlobStreamSource::GetBlob => println!("Using fallback blob path"), } ``` -------------------------------- ### Handle I/O Errors Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/errors.md Example of how to match and handle `Error::Io` variants, specifically checking for `ErrorKind::BrokenPipe`. ```rust match result { Err(Error::Io(e)) if e.kind() == std::io::ErrorKind::BrokenPipe => { eprintln!("Socket disconnected"); } Err(Error::Io(e)) => eprintln!("I/O error: {}", e), _ => {} } ``` -------------------------------- ### Handle SerDe Errors Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/errors.md Example demonstrating how to catch and report `Error::SerDe` errors that occur during JSON parsing of manifests or responses. ```rust match proxy.fetch_manifest(&img).await { Err(Error::SerDe(e)) => eprintln!("Manifest JSON parsing failed: {}", e), _ => {} } ``` -------------------------------- ### Handle Request Initiation Failures Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/errors.md Example for handling `Error::RequestInitiationFailure`, showing how to extract the method name and error message when an RPC call fails. ```rust match proxy.open_image("invalid://reference").await { Err(Error::RequestInitiationFailure { method, error }) => { eprintln!("Method {} failed: {}", method, error); } _ => {} } ``` -------------------------------- ### BlobStream into_parts() Method Example Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/types.md Consumes the BlobStream to extract the reader and driver future for custom handling. ```rust let stream = proxy.get_blob_stream(&img, &digest, size).await?; let (reader, driver) = stream.into_parts(); // Custom polling let copy_result = tokio::io::copy(&mut reader, &mut output).await?; driver.await?; // Verify after reading ``` -------------------------------- ### Configure Custom User-Agent Prefix Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/configuration.md Customize the User-Agent header sent to registries by setting a prefix. This is applied if the installed skopeo version supports the `--user-agent-prefix` flag. ```rust let mut config = ImageProxyConfig::default(); config.user_agent_prefix = Some("myapp/1.0".to_string()); let proxy = ImageProxy::new_with_config(config).await?; ``` -------------------------------- ### Get Layer Info and Iterate Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/types.md Retrieves information about image layers and iterates through them. Ensure the proxy is initialized and the image reference is valid before calling. ```rust if let Some(layers) = proxy.get_layer_info(&img).await? { for layer_info in layers { println!("Layer digest: {}", layer_info.digest); println!("Uncompressed size: {} bytes", layer_info.size); println!("Media type: {}", layer_info.media_type); } } ``` -------------------------------- ### Handle ProxyTooOld Error Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/errors.md This snippet demonstrates how to match and handle the `ProxyTooOld` error, which occurs when the installed skopeo version is too old for the required protocol version. It prints a user-friendly message indicating the required and found versions. ```rust match ImageProxy::new().await { Err(Error::ProxyTooOld { requested_version, found_version }) => { eprintln!("Upgrade skopeo: need {}, found {}", requested_version, found_version); } _ => {} } ``` -------------------------------- ### Handle Other GetBlobError Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/errors.md Example of how to match and handle an Other error from a future. This indicates a permanent failure that should not be retried. ```rust match err_future.await { Err(GetBlobError::Other(msg)) => { eprintln!("Permanent error: {}", msg); } _ => {} } ``` -------------------------------- ### ImageProxy Initialization and Lifecycle Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/architecture.md Describes the `new_with_config` function for initializing the ImageProxy, which involves creating a socket pair, spawning skopeo, and sending an 'Initialize' request. The `finalize` function handles sending a 'Shutdown' request and waiting for the child process to exit. ```text new_with_config() ├─ Create socket pair (parent ↔ child) ├─ Spawn skopeo with socket as stdin ├─ spawn_blocking task for child.wait_with_output() ├─ Send "Initialize" request ├─ Parse protocol version ├─ Verify version matches min requirement └─ Return initialized ImageProxy [Multiple operations...] finalize() ├─ Send "Shutdown" request ├─ Wait for child process exit ├─ Check exit status └─ Consume self (ownership transfer) ``` -------------------------------- ### Create ImageProxy with Custom Configuration Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Use `ImageProxy::new_with_config()` to create an instance with explicit configuration. This is useful for specifying authentication, TLS settings, or custom skopeo commands. Ensure the configuration is valid to avoid errors related to conflicting auth options or invalid FD allocation. Errors can also occur if the subprocess fails to spawn or if there's a protocol version mismatch. ```rust let mut config = ImageProxyConfig::default(); config.insecure_skip_tls_verification = Some(true); config.debug = true; let proxy = ImageProxy::new_with_config(config).await?; ``` -------------------------------- ### Get Proxy Protocol Version Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Retrieves the semantic version of the remote proxy protocol. Use this for feature detection and compatibility checks. ```rust pub fn protocol_version(&self) -> &semver::Version ``` ```rust let version = proxy.protocol_version(); println!("Proxy protocol: {}", version); ``` -------------------------------- ### ImageProxy::new() Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Creates an image proxy using default configuration. This method automatically spawns a skopeo subprocess and negotiates the protocol version. ```APIDOC ## new() ### Description Creates an image proxy using default configuration. Automatically spawns a skopeo subprocess and performs protocol version negotiation. ### Signature ```rust pub async fn new() -> Result ``` ### Returns `Result` — Success with initialized proxy, or error if skopeo spawn or version check fails. ### Errors - `Error::SkopeoSpawnError` — skopeo binary not found or cannot be executed - `Error::ProxyTooOld` — installed skopeo version below minimum (0.2.3) ### Example ```rust let proxy = ImageProxy::new().await?; ``` ``` -------------------------------- ### Image Opening and Manifest Fetch Data Flow Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/architecture.md Illustrates the sequence of operations for opening an image and fetching its manifest using the proxy. Includes sending requests, receiving responses, and handling file descriptors for manifest data. ```text Client Application │ ├─ ImageProxy::new_with_config() │ │ │ ├─ Spawn skopeo subprocess │ ├─ Perform protocol version handshake │ └─ Return ImageProxy instance │ ├─ open_image(reference) │ │ │ ├─ Send: {"method": "OpenImage", "args": ["docker://..."]} │ ├─ Receive: {"success": true, "value": } │ └─ Return: OpenedImage() │ ├─ fetch_manifest(&img) │ │ │ ├─ Send: {"method": "GetManifest", "args": []} │ ├─ Receive: {"success": true, "pipeid": N, "value": } │ │ + FD for manifest data │ ├─ Read manifest JSON from FD │ ├─ Send: {"method": "FinishPipe", "args": [N]} │ └─ Return: (digest, parsed_manifest) │ └─ close_image(&img) │ ├─ Send: {"method": "CloseImage", "args": []} └─ Receive: {"success": true} ``` -------------------------------- ### Handle Retryable GetBlobError Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/errors.md Example of how to match and handle a Retryable error from a future. This pattern is useful for implementing retry logic for transient failures. ```rust match err_future.await { Err(GetBlobError::Retryable(msg)) => { eprintln!("Retryable error: {}; consider retrying...", msg); // Retry logic } _ => {} } ``` -------------------------------- ### ImageProxy::new_with_config(config: ImageProxyConfig) Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Creates an image proxy with explicit configuration, allowing for custom settings like authentication, TLS, or specific skopeo commands. ```APIDOC ## new_with_config(config: ImageProxyConfig) ### Description Creates an image proxy with explicit configuration. Useful for specifying authentication, TLS settings, or custom skopeo commands. ### Signature ```rust pub async fn new_with_config(config: ImageProxyConfig) -> Result ``` ### Parameters #### Path Parameters - **config** (ImageProxyConfig) - Required - Configuration builder with all proxy options ### Returns `Result` — Success with initialized proxy, or error if configuration is invalid or spawn fails. ### Errors - `Error::Configuration` — conflicting auth options or invalid FD allocation - `Error::SkopeoSpawnError` — subprocess spawn failure - `Error::ProxyTooOld` — protocol version mismatch ### Example ```rust let mut config = ImageProxyConfig::default(); config.insecure_skip_tls_verification = Some(true); config.debug = true; let proxy = ImageProxy::new_with_config(config).await?; ``` ``` -------------------------------- ### Handle Request Returned Errors Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/errors.md Example for handling `Error::RequestReturned`, which indicates a successful request initiation but an error during execution, often from the remote proxy. ```rust match proxy.finalize().await { Err(Error::RequestReturned(msg)) => { eprintln!("Proxy exited with error: {}", msg); } _ => {} } ``` -------------------------------- ### Open Image from Container Storage Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/usage-examples.md Demonstrates opening an image from a local container storage using both string and programmatic image references. It fetches the manifest and prints the number of layers. ```rust use containers_image_proxy::{ImageProxy, ImageReference, Transport}; #[tokio::main] async fn main() -> anyhow::Result<()> { let proxy = ImageProxy::new().await?; // Method 1: String reference let img = proxy.open_image("containers-storage:localhost/myimage:latest").await?; // Method 2: Programmatic reference let imgref = ImageReference::new( Transport::ContainerStorage, "localhost/myimage:latest" ); let img2 = proxy.open_image_ref(&imgref).await?; let (digest, manifest) = proxy.fetch_manifest(&img).await?; println!("Container storage image: {}", digest); println!("Layers: {}", manifest.layers().len()); proxy.close_image(&img).await?; proxy.close_image(&img2).await?; proxy.finalize().await?; Ok(()) } ``` -------------------------------- ### ImageProxyConfig to Command Translation Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/architecture.md Illustrates the translation of ImageProxyConfig into a skopeo command, including default wrappers, authentication, certificate, decryption, TLS, signature, user agent, and debug options. The socket file descriptor is passed via stdin. ```text ImageProxyConfig │ ├─ [Default wrapper: setpriv --pdeathsig SIGTERM] │ (Or custom skopeo_cmd if provided) │ ├─ + "experimental-image-proxy" │ ├─ + auth options (--authfile or --no-creds) │ ├─ + cert options (--cert-dir) │ ├─ + decryption options (--decryption-key ...) │ ├─ + TLS options (--tls-verify=false if insecure) │ ├─ + signature options (--insecure-policy) │ ├─ + user agent (--user-agent-prefix if supported) │ ├─ + debug (--debug if enabled) │ └─ + stdin: socket FD ``` -------------------------------- ### Configuration Options Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/README.md Details on available configuration options for the ImageProxy. ```APIDOC ## ImageProxy Configuration ### Description Provides details on the various configuration options available for customizing the ImageProxy's behavior. ### Key Configuration Areas - **Authentication**: Supports multiple modes including file-based, stream-based, and anonymous authentication. - **TLS/Certificates**: Options for configuring TLS and certificate handling. - **Image Decryption**: Settings related to decrypting images. - **User-Agent**: Customization of the User-Agent string sent in requests. - **Debug Logging**: Enabling and configuring debug logging. - **Custom Command Wrapping**: Options for wrapping commands executed by the proxy. ``` -------------------------------- ### Open and Inspect OCI Directory Image Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/usage-examples.md Opens an image from a local OCI directory layout, fetches its manifest, and prints layer information. Ensure the OCI directory and tag exist. ```rust use containers_image_proxy::ImageProxy; #[tokio::main] async fn main() -> anyhow::Result<()> { let proxy = ImageProxy::new().await?; // Reference a local OCI directory let oci_ref = "oci:/var/lib/containers/ocidir:mytag"; let img = proxy.open_image(oci_ref).await?; let (digest, manifest) = proxy.fetch_manifest(&img).await?; println!("OCI image digest: {}", digest); println!("Layers: {}", manifest.layers().len()); proxy.close_image(&img).await?; proxy.finalize().await?; Ok(()) } ``` -------------------------------- ### Try Create Registry ImageReference with try_new_registry() Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/transport.md Attempts to create a Registry ImageReference by parsing the provided string as an OCI distribution reference. This method returns an error for invalid reference formats. ```rust let imgref = ImageReference::try_new_registry("quay.io/example/image:latest")?; assert_eq!(imgref.to_string(), "docker://quay.io/example/image:latest"); // Invalid references fail assert!(ImageReference::try_new_registry("not a valid reference!").is_err()); ``` -------------------------------- ### Open Image by Reference String Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Opens a container image using a transport-qualified reference string. The reference format depends on the transport (e.g., `docker://`, `oci:`). Errors can occur due to invalid references, image not found, remote proxy issues, or socket communication problems. ```rust pub async fn open_image(&self, imgref: &str) -> Result ``` ```rust let img = proxy.open_image("docker://quay.io/fedora/fedora:latest").await?; ``` -------------------------------- ### Module Organization in containers-image-proxy-rs Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/overview.md Illustrates the high-level structure of the library's modules and their responsibilities. ```text imageproxy (library root) ├── transport - Image reference parsing and validation ├── ImageProxy - Subprocess management and RPC client ├── Error types - Comprehensive error enumeration ├── Configuration - ImageProxyConfig builder struct └── Types - ConvertedLayerInfo, BlobStream, etc. ``` -------------------------------- ### Open Image Optionally (String Reference) Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Attempts to open an image by its string reference. Returns `Ok(None)` if the image does not exist, distinguishing it from other errors like remote proxy failures or I/O issues. ```rust pub async fn open_image_optional(&self, imgref: &str) -> Result> ``` ```rust let img_opt = proxy.open_image_optional("oci:/path/to/archive:tag").await?; match img_opt { Some(img) => println!("Image found"), None => println!("Image not found"), } ``` -------------------------------- ### Fetch Raw Image Configuration Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Fetches the image config blob as raw bytes. Use this when you need the raw configuration data. ```rust pub async fn fetch_config_raw(&self, img: &OpenedImage) -> Result> ``` -------------------------------- ### Fetch Container Image Metadata Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/usage-examples.md Fetches and displays a container image's manifest and configuration details, including architecture and layer information. Requires `tokio` for async operations. ```rust use containers_image_proxy::ImageProxy; #[tokio::main] async fn main() -> anyhow::Result<()> { // Create proxy with default configuration let proxy = ImageProxy::new().await?; // Open an image let img = proxy.open_image("docker://quay.io/fedora/fedora:latest").await?; // Fetch manifest and config let (digest, manifest) = proxy.fetch_manifest(&img).await?; let config = proxy.fetch_config(&img).await?; println!("Manifest digest: {}", digest); println!("Architecture: {}", config.architecture()); // Display layer information for (i, layer) in manifest.layers().iter().enumerate() { println!("Layer {}: {} ({} bytes)", i, layer.digest(), layer.size() ); } proxy.close_image(&img).await?; proxy.finalize().await?; Ok(()) } ``` -------------------------------- ### fetch_config Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Fetches and deserializes the image configuration. ```APIDOC ## fetch_config ### Description Fetches and deserializes the image configuration. ### Parameters #### Path Parameters - **img** (OpenedImage) - Required - Opened image handle ### Returns - **oci_spec::image::ImageConfiguration** - Parsed configuration struct ### Errors - Error::RequestReturned - fetch failed - Error::SerDe - deserialization error ### Example ```rust let config = proxy.fetch_config(&img).await?; println!("Arch: {}", config.architecture()); println!("Env: {:?}", config.config().and_then(|c| c.env())); ``` ``` -------------------------------- ### Open Image Optionally (ImageReference) Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Attempts to open an image using a structured `ImageReference`. Returns `Ok(None)` if the image is not found, differentiating this case from other potential errors. ```rust pub async fn open_image_optional_ref(&self, imgref: &ImageReference) -> Result> ``` -------------------------------- ### Custom Authentication with Image Proxy Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/usage-examples.md Configure the ImageProxy with custom authentication using either a file path or a file stream. This is useful for authenticating with private registries. ```rust use containers_image_proxy::{ImageProxy, ImageProxyConfig}; use std::path::PathBuf; use std::fs::File; #[tokio::main] async fn main() -> anyhow::Result<()> { let mut config = ImageProxyConfig::default(); // Option 1: File path config.authfile = Some(PathBuf::from("/etc/containers/auth.json")); // Or Option 2: File stream (for privilege separation) // config.auth_data = Some(File::open("/run/secrets/auth.json")?); let proxy = ImageProxy::new_with_config(config).await?; // Now fetch from private registry let img = proxy.open_image("docker://registry.example.com/private/image:tag").await?; let (_, manifest) = proxy.fetch_manifest(&img).await?; println!("Successfully authenticated and fetched {} layers", manifest.layers().len() ); proxy.close_image(&img).await?; proxy.finalize().await?; Ok(()) } ``` -------------------------------- ### Image Opening and Handling Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/MANIFEST.md Methods for opening images using string references or ImageReference objects, and for closing opened image handles. ```APIDOC ## ImageProxy::open_image(ref) ### Description Opens an image using its string reference. ### Method `ImageProxy::open_image(ref: &str)` ### Parameters - **ref** (`&str`) - Required - The string reference of the image to open. ### Response - Returns an `Result`. ### Request Example ```rust match proxy.open_image("docker://ubuntu:latest") { Ok(image) => { // Use the opened image proxy.close_image(&image)?; }, Err(e) => eprintln!("Error opening image: {}", e), } ``` ## ImageProxy::open_image_ref(imgref) ### Description Opens an image using an `ImageReference` object. ### Method `ImageProxy::open_image_ref(imgref: &ImageReference)` ### Parameters - **imgref** (`&ImageReference`) - Required - The `ImageReference` object pointing to the image. ### Response - Returns an `Result`. ### Request Example ```rust let imgref = ImageReference::try_new("docker://alpine:latest")?; match proxy.open_image_ref(&imgref) { Ok(image) => { // Use the opened image proxy.close_image(&image)?; }, Err(e) => eprintln!("Error opening image: {}", e), } ``` ## ImageProxy::open_image_optional(ref) ### Description Opens an image using its string reference, returning `None` if the image does not exist. ### Method `ImageProxy::open_image_optional(ref: &str)` ### Parameters - **ref** (`&str`) - Required - The string reference of the image to open. ### Response - Returns an `Option`. ### Request Example ```rust if let Some(image) = proxy.open_image_optional("docker://nonexistent:tag") { // Image found and opened proxy.close_image(&image)?; } else { println!("Image not found."); } ``` ## ImageProxy::open_image_optional_ref(imgref) ### Description Opens an image using an `ImageReference` object, returning `None` if the image does not exist. ### Method `ImageProxy::open_image_optional_ref(imgref: &ImageReference)` ### Parameters - **imgref** (`&ImageReference`) - Required - The `ImageReference` object pointing to the image. ### Response - Returns an `Option`. ### Request Example ```rust let imgref = ImageReference::try_new("docker://another:tag")?; if let Some(image) = proxy.open_image_optional_ref(&imgref) { // Image found and opened proxy.close_image(&image)?; } else { println!("Image not found."); } ``` ## ImageProxy::close_image(img) ### Description Closes an opened image handle, releasing associated resources. ### Method `ImageProxy::close_image(img: &OpenedImage)` ### Parameters - **img** (`&OpenedImage`) - Required - The handle to the image to close. ### Response - Returns `Ok(())` on success, or an `Error` on failure. ### Request Example ```rust let image = proxy.open_image("docker://ubuntu:latest")?; proxy.close_image(&image)?; ``` ``` -------------------------------- ### OpenedImage Handling Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/architecture.md Explains the lifecycle of an opened image. `open_image` returns an opaque handle, which is then used for operations like fetching manifests or blobs. `close_image` sends a 'CloseImage' request with the image ID. ```text open_image(ref) └─ Return OpenedImage() opaque handle [Use in fetch_manifest, get_blob, etc.] close_image(img) └─ Send "CloseImage" request with id ``` -------------------------------- ### ImageProxy Construction Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/MANIFEST.md Methods for creating new ImageProxy instances, either with default settings or custom configurations. ```APIDOC ## ImageProxy::new() ### Description Creates a new ImageProxy instance with default configuration. ### Method `ImageProxy::new()` ### Parameters None ### Response - Returns an `ImageProxy` instance. ### Request Example ```rust let proxy = ImageProxy::new(); ``` ## ImageProxy::new_with_config(config) ### Description Creates a new ImageProxy instance with a custom configuration. ### Method `ImageProxy::new_with_config(config: ImageProxyConfig)` ### Parameters - **config** (`ImageProxyConfig`) - Required - The configuration object for the ImageProxy. ### Response - Returns an `ImageProxy` instance. ### Request Example ```rust let config = ImageProxyConfig::default(); // or a custom config let proxy = ImageProxy::new_with_config(config); ``` ``` -------------------------------- ### ImageProxyConfig Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/types.md Configuration builder for customizing proxy behavior. All fields are optional. ```APIDOC ## ImageProxyConfig Struct Configuration builder for customizing proxy behavior. All fields are optional. See [configuration.md](configuration.md) for detailed field descriptions. **Import path**: `containers_image_proxy::ImageProxyConfig` **Source file**: `src/imageproxy.rs:404-464` ``` -------------------------------- ### Configure Custom skopeo Command Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/configuration.md Wrap the skopeo command with additional tools for containerization or privilege separation. The custom command must have 'skopeo' as the primary executable and support specific redirection methods. ```rust use std::process::Command; use std::os::unix::process::CommandExt; let mut config = ImageProxyConfig::default(); let mut cmd = Command::new("systemd-run"); cmd.args(&["-Pq", "-p", "DynamicUser=yes", "--", "skopeo"]); config.skopeo_cmd = Some(cmd); let proxy = ImageProxy::new_with_config(config).await?; ``` -------------------------------- ### File-Based Authentication for Image Proxy Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/configuration.md Configure the proxy to read credentials from a specified file path. Ensure the file exists and contains valid authentication data. ```rust let mut config = ImageProxyConfig::default(); config.authfile = Some(PathBuf::from("/home/user/.docker/config.json")); let proxy = ImageProxy::new_with_config(config).await?; ``` -------------------------------- ### Process Layers Concurrently with ImageProxy Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/usage-examples.md Demonstrates parallel processing of image layers using futures and tokio. It fetches blobs concurrently, limiting the number of parallel tasks. ```rust use containers_image_proxy::ImageProxy; use futures::stream::{self, StreamExt}; use std::fs::File; use std::io::Write; #[tokio::main] async fn main() -> anyhow::Result<()> { let proxy = std::sync::Arc::new(ImageProxy::new().await?); let img_ref = "docker://ubuntu:latest"; // Convert proxy to Arc for sharing across tasks let proxy_clone = proxy.clone(); let img = proxy_clone.open_image(img_ref).await?; let (_, manifest) = proxy.fetch_manifest(&img).await?; // Process layers concurrently (limit to 3 at a time) let results = stream::iter(manifest.layers().iter().enumerate()) .map(|(i, layer)| { let proxy = proxy.clone(); let digest = layer.digest().clone(); let size = layer.size(); async move { match proxy.get_blob(&img, &digest, size).await { Ok((mut blob, driver)) => { let mut data = Vec::new(); blob.read_to_end(&mut data).await.ok(); driver.await.ok(); Ok((i, data.len())) } Err(e) => Err((i, e)), } } }) .buffer_unordered(3) .collect::>() .await; for result in results { match result { Ok((i, size)) => println!("Layer {}: {} bytes", i, size), Err((i, e)) => println!("Layer {}: error {}", i, e), } } proxy.close_image(&img).await?; proxy.finalize().await?; Ok(()) } ``` -------------------------------- ### Fetch Blob with Verification (Rust) Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Fetches a blob with proxy-side verification. Use tokio::join!() to poll both the reader and driver futures concurrently. The driver future completes only after the blob has been fully read and verified. ```rust pub async fn get_blob( &self, img: &OpenedImage, digest: &Digest, size: u64, ) -> Result<( impl AsyncBufRead + Send + Unpin, impl Future> + Unpin + '_, )> ``` ```rust let (mut blob, driver) = proxy.get_blob(&img, digest, size).await?; let mut buffer = [0u8; 8192]; let reader = async { let mut all = Vec::new(); loop { let n = blob.read(&mut buffer).await?; if n == 0 { break; } all.extend_from_slice(&buffer[..n]); } Ok(all) }; let (data, ()) = tokio::join!(reader, driver); let blob_bytes = data?; ``` -------------------------------- ### open_image_optional Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Attempts to open a container image by its reference string. If the image does not exist, it returns `Ok(None)` instead of an error. ```APIDOC ## open_image_optional(imgref: &str) ### Description Attempts to open an image, returning `Ok(None)` if the image does not exist instead of an error. ### Method `async fn open_image_optional(&self, imgref: &str) -> Result> ### Parameters #### Path Parameters - **imgref** (string) - Required - Transport-qualified image reference ### Returns `Result>` — Some(handle) if image exists, None if not found, Err on other failures ### Errors - `Error::RequestReturned` — failure other than "not found" - `Error::Io` — socket communication error ### Example ```rust let img_opt = proxy.open_image_optional("oci:/path/to/archive:tag").await?; match img_opt { Some(img) => println!("Image found"), None => println!("Image not found"), } ``` ``` -------------------------------- ### Custom Certificate Directory for Image Proxy Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/configuration.md Specify a directory containing custom CA certificates, client certificates, or client keys for TLS connections. ```rust let mut config = ImageProxyConfig::default(); config.certificate_directory = Some(PathBuf::from("/etc/custom-certs")); let proxy = ImageProxy::new_with_config(config).await?; ``` -------------------------------- ### Configure Image Decryption Keys Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/configuration.md Specify paths to decryption key files for encrypted container images. Multiple keys can be provided if the image uses key encryption. ```rust let mut config = ImageProxyConfig::default(); config.decryption_keys = Some(vec![ "/etc/secrets/key1.txt".to_string(), "/etc/secrets/key2.txt".to_string(), ]); let proxy = ImageProxy::new_with_config(config).await?; ``` -------------------------------- ### fetch_config_raw Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Fetches the image config blob as raw bytes. ```APIDOC ## fetch_config_raw ### Description Fetches the image config blob as raw bytes. ### Parameters #### Path Parameters - **img** (OpenedImage) - Required - Opened image handle ### Returns - **Vec** - Raw config JSON bytes ### Errors - Same as `fetch_manifest_raw_oci()` ``` -------------------------------- ### Create Registry ImageReference with new_registry() Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/transport.md Creates an ImageReference with the Registry transport from a pre-parsed OCI Reference. Ensure the OCI reference is correctly parsed before use. ```rust let oci_ref: oci_spec::distribution::Reference = "quay.io/example/image:latest".parse()?; let imgref = ImageReference::new_registry(oci_ref); assert_eq!(imgref.transport, Transport::Registry); ``` -------------------------------- ### Handle Insecure/Untrusted Registry Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/usage-examples.md Shows how to configure the ImageProxy to work with insecure or untrusted registries, such as those using self-signed certificates. It demonstrates skipping TLS verification. ```rust use containers_image_proxy::{ImageProxy, ImageProxyConfig}; #[tokio::main] async fn main() -> anyhow::Result<()> { let mut config = ImageProxyConfig::default(); // Skip TLS verification (use only for testing/trusted networks) config.insecure_skip_tls_verification = Some(true); // Or provide custom CA certificates // config.certificate_directory = Some(PathBuf::from("/etc/custom-ca")); let proxy = ImageProxy::new_with_config(config).await?; let img = proxy.open_image("docker://internal-registry.local/image:latest").await?; let (_, manifest) = proxy.fetch_manifest(&img).await?; println!("Fetched {} layers", manifest.layers().len()); proxy.close_image(&img).await?; proxy.finalize().await?; Ok(()) } ``` -------------------------------- ### Fetch Blob as Stream (Rust) Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Fetches a blob as a stream, automatically using GetRawBlob with verification if available, otherwise falling back to GetBlob. Recommended for most use cases. ```rust pub async fn get_blob_stream<'a>( &'a self, img: &OpenedImage, digest: &Digest, expected_size: u64, ) -> Result> ``` ```rust let stream = proxy.get_blob_stream(&img, digest, size).await?; let (mut reader, driver) = stream.into_parts(); let copier = tokio::io::copy(&mut reader, &mut output); let (_, ()) = tokio::join!(copier, driver); println!("Source: {:?}", stream.source()); ``` -------------------------------- ### open_image Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Opens a container image using its reference string. The format of the reference string depends on the transport protocol (e.g., `docker://`, `oci:`). ```APIDOC ## open_image(imgref: &str) ### Description Opens a container image by reference string. The reference format depends on the transport (docker://, oci:, etc.). ### Method `async fn open_image(&self, imgref: &str) -> Result ### Parameters #### Path Parameters - **imgref** (string) - Required - Transport-qualified image reference, e.g., "docker://quay.io/exampleos/blah:tag" ### Returns `Result` — Opaque handle to the opened image ### Errors - `Error::RequestInitiationFailure` — invalid reference format or image not found - `Error::RequestReturned` — remote proxy error - `Error::Io` — socket communication error ### Example ```rust let img = proxy.open_image("docker://quay.io/fedora/fedora:latest").await?; ``` ``` -------------------------------- ### ImageProxyConfig Structure Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/configuration.md Defines the structure for customizing image proxy behavior. All fields are optional and have sensible defaults. ```rust #[derive(Debug, Default)] pub struct ImageProxyConfig { pub authfile: Option, pub auth_data: Option, pub auth_anonymous: bool, pub certificate_directory: Option, pub decryption_keys: Option>, pub insecure_skip_tls_verification: Option, pub insecure_policy: Option, pub user_agent_prefix: Option, pub debug: bool, pub skopeo_cmd: Option, } ``` -------------------------------- ### Fetch Deserialized Image Configuration Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Fetches and deserializes the image configuration into an ImageConfiguration struct. Use this to easily access configuration details like architecture or environment variables. Returns the parsed configuration struct. ```rust pub async fn fetch_config( &self, img: &OpenedImage, ) -> Result ``` ```rust let config = proxy.fetch_config(&img).await?; println!("Arch: {}", config.architecture()); println!("Env: {:?}", config.config().and_then(|c| c.env())); ``` -------------------------------- ### Access Local Docker Daemon Image Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/usage-examples.md Opens an image from the local Docker daemon using the ImageProxy. Ensure the Docker daemon is accessible. ```rust use containers_image_proxy::ImageProxy; #[tokio::main] async fn main() -> anyhow::Result<()> { let proxy = ImageProxy::new().await?; // Reference local Docker daemon image let img = proxy.open_image("docker-daemon:myapp:latest").await?; let (digest, manifest) = proxy.fetch_manifest(&img).await?; println!("Docker daemon image: {}", digest); println!("Layers: {}", manifest.layers().len()); proxy.close_image(&img).await?; proxy.finalize().await?; Ok(()) } ``` -------------------------------- ### Fetch Layer Information and Diffids Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/usage-examples.md Use this snippet to retrieve layer metadata, including compressed digest, uncompressed size, and media type. Ensure the image proxy is initialized and the image is opened before calling this function. The proxy and image should be closed and finalized afterwards. ```rust use containers_image_proxy::ImageProxy; #[tokio::main] async fn main() -> anyhow::Result<()> { let proxy = ImageProxy::new().await?; let img = proxy.open_image("docker://ubuntu:22.04").await?; // Get layer info (includes diffids) if let Some(layers) = proxy.get_layer_info(&img).await? { for (i, layer) in layers.iter().enumerate() { println!("Layer {}:", i); println!(" Compressed digest: {}", layer.digest); println!(" Uncompressed size: {} bytes", layer.size); println!(" Media type: {}", layer.media_type); } } else { println!("Layer info not supported by proxy"); } proxy.close_image(&img).await?; proxy.finalize().await?; Ok(()) } ``` -------------------------------- ### fetch_manifest Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Fetches the manifest as a deserialized OCI ImageManifest struct. Returns both original digest and parsed manifest. ```APIDOC ## fetch_manifest ### Description Fetches the manifest as a deserialized OCI ImageManifest struct. Returns both original digest and parsed manifest. ### Parameters #### Path Parameters - **img** (OpenedImage) - Required - Opened image handle ### Returns - **String** - Digest - **oci_spec::image::ImageManifest** - Parsed manifest ### Errors - Error::RequestReturned - manifest fetch failed - Error::SerDe - manifest JSON deserialization error - Error::Io - socket error ### Example ```rust let (digest, manifest) = proxy.fetch_manifest(&img).await?; println!("Digest: {}", digest); for layer in manifest.layers() { println!("Layer: {} ({} bytes)", layer.digest(), layer.size()); } ``` ``` -------------------------------- ### get_blob() Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Fetches a blob with verification performed by the proxy process. Returns a tuple of (reader, driver_future). The driver future completes only after the blob has been fully read and verified. Use tokio::join!() to poll both futures concurrently. ```APIDOC ## get_blob() ### Description Fetches a blob with verification performed by the proxy process. Returns a tuple of (reader, driver_future). The driver future completes only after the blob has been fully read and verified. ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Method Signature ```rust pub async fn get_blob( &self, img: &OpenedImage, digest: &Digest, size: u64, ) -> Result<(impl AsyncBufRead + Send + Unpin, impl Future> + Unpin + '_)> ``` ### Returns Tuple of (AsyncBufRead, Future) — reader and completion future ### Errors - `Error::RequestReturned` — blob not found or fetch failed - `Error::Io` — socket or file error ### Example ```rust let (mut blob, driver) = proxy.get_blob(&img, digest, size).await?; let mut buffer = [0u8; 8192]; let reader = async { let mut all = Vec::new(); loop { let n = blob.read(&mut buffer).await?; if n == 0 { break; } all.extend_from_slice(&buffer[..n]); } Ok(all) }; let (data, ()) = tokio::join!(reader, driver); let blob_bytes = data?; ``` ``` -------------------------------- ### ImageReference::try_new_registry Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/transport.md Attempts to create a registry reference by parsing a given string as an OCI distribution reference. ```APIDOC ## ImageReference::try_new_registry ### Description Creates a registry reference by parsing the name string as an OCI distribution reference. ### Method `ImageReference::try_new_registry(name: &str) -> Result` ### Parameters #### Path Parameters - **name** (&str) - Required - Image name to parse (e.g., "quay.io/example/image:latest") ### Response - `Result` - Reference or parse error ### Request Example ```rust let imgref = ImageReference::try_new_registry("quay.io/example/image:latest")?; assert_eq!(imgref.to_string(), "docker://quay.io/example/image:latest"); // Invalid references fail assert!(ImageReference::try_new_registry("not a valid reference!").is_err()); ``` ``` -------------------------------- ### open_image_optional_ref Source: https://github.com/bootc-dev/containers-image-proxy-rs/blob/main/_autodocs/imageproxy.md Attempts to open an image using a structured `ImageReference`. Returns `Ok(None)` if the image is not found, otherwise returns the opened image handle or an error. ```APIDOC ## open_image_optional_ref(imgref: &ImageReference) ### Description Opens an image using `ImageReference`, returning `Ok(None)` if not found. ### Method `async fn open_image_optional_ref(&self, imgref: &ImageReference) -> Result> ### Parameters #### Path Parameters - **imgref** (`ImageReference`) - Required - Parsed image reference ### Returns `Result>` — Some(handle) if found, None if missing, Err on other failures ```