Visitar URL original
🐞 regression: `container.withAnnotation` on multiarch iamge does not add annotations to image variants · Issue #15087 · dagger/dagger · GitHub
Skip to content

🐞 regression: container.withAnnotation on multiarch iamge does not add annotations to image variants #15087

Open

Description

@cbochs

What is the issue?

If you place an OCI annotation on a container that is used for publishing multiple platform variants, for example,

container
  .withAnnotation("org.opencontainers.image.description", "asdf")
  .publish("...", platformVariants: variants)

You will find the the annotation is dropped and does not appear in any of: the image index, index manifests, nor the image manifests. For example,

# Used `.withAnnotation` on the multiarch image, annotations dropped
oras manifest fetch ghcr.io/cbochs/gift-exchange:v1.0.1

# Used `.withAnnotation` on the image variants, annotations kept
oras manifest fetch ghcr.io/cbochs/gift-exchange:v1.0.2

In the past (#10330 (comment)) the index manifests and image manifests were annotated. This is not the case anymore. If the variants themselves are annotated individually with .withAnnotation then an annotation appears (see repro).

Dagger version

v1.0.0-beta.25

Steps to reproduce

Example repro module
"""
Reproduce annotation placement on multi-platform image publishes.
"""
type AnnotationRepro {
  publishAndInspect: String! {
    let registry = container
      .from("registry:2.8.3")
      .withExposedPort(5000)
      .asService

    let annotatedVariants = ["linux/amd64", "linux/arm64"].map { platform =>
      container(platform: platform :: Platform!)
        .withNewFile("/platform.txt", platform)
        .withAnnotation("org.opencontainers.image.description", "variant-" + platform)
    }

    let plainVariants = ["linux/amd64", "linux/arm64"].map { platform =>
      container(platform: platform :: Platform!)
        .withNewFile("/platform.txt", platform)
    }

    let variantImage = container
      .publish(
        "registry:5000/repro/variant-annotations:latest",
        platformVariants: annotatedVariants,
        registryService: registry,
        protocol: HTTP,
      )

    let parentImage = container
      .withAnnotation("org.opencontainers.image.description", "parent-only")
      .publish(
        "registry:5000/repro/parent-annotation:latest",
        platformVariants: plainVariants,
        registryService: registry,
        protocol: HTTP,
      )

    let oras = container
      .from("ghcr.io/oras-project/oras:v1.2.3")
      .withServiceBinding("registry", registry)

    let indexTemplate = "index={{if .content.annotations}}{{index .content.annotations \"org.opencontainers.image.description\"}}{{else}}(none){{end}}; descriptors={{range .content.manifests}}{{.platform.architecture}}={{if .annotations}}{{index .annotations \"org.opencontainers.image.description\"}}{{else}}(none){{end}} {{end}}"
    let manifestTemplate = "{{if .content.annotations}}{{index .content.annotations \"org.opencontainers.image.description\"}}{{else}}(none){{end}}"

    let variantIndex = oras.withExec(["/bin/oras", "manifest", "fetch", "--plain-http", "--format", "go-template", "--template", indexTemplate, variantImage]).stdout
    let variantAMD64 = oras.withExec(["/bin/oras", "manifest", "fetch", "--plain-http", "--platform", "linux/amd64", "--format", "go-template", "--template", manifestTemplate, variantImage]).stdout
    let variantARM64 = oras.withExec(["/bin/oras", "manifest", "fetch", "--plain-http", "--platform", "linux/arm64", "--format", "go-template", "--template", manifestTemplate, variantImage]).stdout

    let parentIndex = oras.withExec(["/bin/oras", "manifest", "fetch", "--plain-http", "--format", "go-template", "--template", indexTemplate, parentImage]).stdout
    let parentAMD64 = oras.withExec(["/bin/oras", "manifest", "fetch", "--plain-http", "--platform", "linux/amd64", "--format", "go-template", "--template", manifestTemplate, parentImage]).stdout
    let parentARM64 = oras.withExec(["/bin/oras", "manifest", "fetch", "--plain-http", "--platform", "linux/arm64", "--format", "go-template", "--template", manifestTemplate, parentImage]).stdout

    ```text
    Annotation on platform variants (org.opencontainers.image.description)
      index + descriptors: ${variantIndex}
      linux/amd64 image manifest: ${variantAMD64}
      linux/arm64 image manifest: ${variantARM64}

    Annotation only on parent multi-platform container
      index + descriptors: ${parentIndex}
      linux/amd64 image manifest: ${parentAMD64}
      linux/arm64 image manifest: ${parentARM64}
    ```
  }
}

Log output

Annotation on platform variants (org.opencontainers.image.description)
  index + descriptors: index=(none); descriptors=amd64=variant-linux/amd64 arm64=variant-linux/arm64
  linux/amd64 image manifest: variant-linux/amd64
  linux/arm64 image manifest: variant-linux/arm64

Annotation only on parent multi-platform container
  index + descriptors: index=(none); descriptors=amd64=(none) arm64=(none)
  linux/amd64 image manifest: (none)
  linux/arm64 image manifest: (none)

Activity

  1. cbochs commented on Nov 5, 2026

    @cbochs
    ContributorAuthor

    I want to take a moment to bring back the issue originally discussed in #10330. If possible, annotations on a multiarch image should be added to an image index. Registries (like ghcr.io) look for annotations like org.opencontainers.image.description to be on the image index to render image details (example). Today, I don't think that is possible using Dagger natively.

  2. dajiaohuang commented on Nov 6, 2026

    @dajiaohuang

    I'd like to investigate and work on this. I'll trace how parent-container annotations flow into multi-platform publish metadata, then add a focused regression test for the expected OCI index/descriptors. If there is an existing in-flight fix or a specific annotation-placement expectation beyond the reproducer, please let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions