diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 32640101..5ee029eb 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -124,6 +124,15 @@ jobs: steps: - uses: earthly/actions-setup@v1 + - name: Earthly login + env: + EARTHLY_SAT_TOKEN: ${{ secrets.EARTHLY_SAT_TOKEN }} + if: env.EARTHLY_SAT_TOKEN != null + run: | + earthly account login --token ${{ secrets.EARTHLY_SAT_TOKEN }} >> /dev/null + earthly org s blue-build + earthly sat s pr + - uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 551064d0..cd330e6b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -154,7 +154,7 @@ jobs: run: | earthly account login --token ${{ secrets.EARTHLY_SAT_TOKEN }} >> /dev/null earthly org s blue-build - earthly sat s pr + earthly sat s main - uses: actions/checkout@v4 with: diff --git a/integration-tests/Earthfile b/integration-tests/Earthfile index fa94bcdd..16ff5a03 100644 --- a/integration-tests/Earthfile +++ b/integration-tests/Earthfile @@ -84,7 +84,7 @@ validate: FROM +test-base RUN --no-cache bluebuild -v validate recipes/recipe.yml - RUN --no-cache bluebuild -v validate recipes/recipe-39.yml + RUN --no-cache bluebuild -v validate recipes/recipe-gts.yml RUN --no-cache bluebuild -v validate recipes/recipe-arm64.yml RUN --no-cache bluebuild -v validate recipes/recipe-invalid.yml && exit 1 || exit 0 RUN --no-cache bluebuild -v validate recipes/recipe-invalid-module.yml && exit 1 || exit 0 diff --git a/process/drivers/docker_driver.rs b/process/drivers/docker_driver.rs index 4a15c5a4..9d927dca 100644 --- a/process/drivers/docker_driver.rs +++ b/process/drivers/docker_driver.rs @@ -1,5 +1,4 @@ use std::{ - collections::HashMap, env, io::Write, path::Path, @@ -21,6 +20,8 @@ use semver::Version; use serde::Deserialize; use tempfile::TempDir; +mod metadata; + use crate::{ drivers::{ opts::{ @@ -35,37 +36,6 @@ use crate::{ signal_handler::{add_cid, remove_cid, ContainerId, ContainerRuntime}, }; -#[derive(Deserialize, Debug, Clone)] -struct DockerImageMetadata { - manifest: DockerImageMetadataManifest, - image: DockerImageMetadataImage, -} - -#[derive(Deserialize, Debug, Clone)] -struct DockerImageMetadataManifest { - digest: String, -} - -#[derive(Deserialize, Debug, Clone)] -struct DockerImageMetadataImage { - config: DockerImageConfig, -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "PascalCase")] -struct DockerImageConfig { - labels: HashMap, -} - -impl From for ImageMetadata { - fn from(value: DockerImageMetadata) -> Self { - Self { - labels: value.image.config.labels, - digest: value.manifest.digest, - } - } -} - #[derive(Debug, Deserialize)] struct DockerVerisonJsonClient { #[serde(alias = "Version")] @@ -396,10 +366,10 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result { bail!("Failed to inspect image {url}") } - serde_json::from_slice::(&output.stdout) + serde_json::from_slice::(&output.stdout) .into_diagnostic() .inspect(|metadata| trace!("{metadata:#?}")) - .map(ImageMetadata::from) + .and_then(|metadata| ImageMetadata::try_from((metadata, opts.platform))) .inspect(|metadata| trace!("{metadata:#?}")) } diff --git a/process/drivers/docker_driver/metadata.rs b/process/drivers/docker_driver/metadata.rs new file mode 100644 index 00000000..75c9d8d0 --- /dev/null +++ b/process/drivers/docker_driver/metadata.rs @@ -0,0 +1,79 @@ +use std::collections::HashMap; + +use miette::{bail, Report}; +use serde::Deserialize; + +use crate::drivers::types::{ImageMetadata, Platform}; + +#[derive(Deserialize, Debug, Clone)] +pub struct Metadata { + manifest: Manifest, + image: MetadataImage, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct PlatformManifest { + digest: String, + platform: PlatformManifestInfo, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct PlatformManifestInfo { + architecture: String, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct Manifest { + digest: String, + + #[serde(default)] + manifests: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct MetadataPlatformImage { + config: Config, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum MetadataImage { + Single(MetadataPlatformImage), + Multi(HashMap), +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "PascalCase")] +pub struct Config { + labels: HashMap, +} + +impl TryFrom<(Metadata, Platform)> for ImageMetadata { + type Error = Report; + + fn try_from((metadata, platform): (Metadata, Platform)) -> Result { + match metadata.image { + MetadataImage::Single(image) => Ok(Self { + labels: image.config.labels, + digest: metadata.manifest.digest, + }), + MetadataImage::Multi(mut platforms) => { + let Some(image) = platforms.remove(&platform.to_string()) else { + bail!("Image information does not exist for {platform}"); + }; + let Some(manifest) = metadata + .manifest + .manifests + .into_iter() + .find(|manifest| manifest.platform.architecture == platform.arch()) + else { + bail!("Manifest does not exist for {platform}"); + }; + Ok(Self { + labels: image.config.labels, + digest: manifest.digest, + }) + } + } + } +} diff --git a/process/drivers/types.rs b/process/drivers/types.rs index 7395ec79..ebc291df 100644 --- a/process/drivers/types.rs +++ b/process/drivers/types.rs @@ -185,9 +185,13 @@ pub enum Platform { impl Platform { /// The architecture of the platform. #[must_use] - pub const fn arch(&self) -> &str { + pub fn arch(&self) -> &str { match *self { - Self::Native => "native", + Self::Native => match std::env::consts::ARCH { + "x86_64" => "amd64", + "aarch64" => "arm64", + arch => unimplemented!("Arch {arch} is unsupported"), + }, Self::LinuxAmd64 => "amd64", Self::LinuxArm64 => "arm64", } @@ -200,7 +204,11 @@ impl std::fmt::Display for Platform { f, "{}", match *self { - Self::Native => "native", + Self::Native => match std::env::consts::ARCH { + "x86_64" => "linux/amd64", + "aarch64" => "linux/arm64", + arch => unimplemented!("Arch {arch} is unsupported"), + }, Self::LinuxAmd64 => "linux/amd64", Self::LinuxArm64 => "linux/arm64", }