diff --git a/build/Build.Pack.cs b/build/Build.Pack.cs index 242508322..836de3b7b 100644 --- a/build/Build.Pack.cs +++ b/build/Build.Pack.cs @@ -727,14 +727,68 @@ void BuildAndPushOrLoadKubernetesTentacleContainerImage(bool push, bool load, st if (includeDebugger) tag += "-debug"; + // Capture one timestamp and reuse it for both the BUILD_DATE build arg (which feeds + // the Dockerfile's org.opencontainers.image.created LABEL) and the created annotation + // below, so the image config and the manifest annotation report the same instant. + var buildDate = DateTime.UtcNow.ToString("O"); + settings = settings - .AddBuildArg($"BUILD_NUMBER={FullSemVer}", $"BUILD_DATE={DateTime.UtcNow:O}", $"RuntimeDepsTag={runtimeDepsImageTag}") + .AddBuildArg($"BUILD_NUMBER={FullSemVer}", $"BUILD_DATE={buildDate}", $"RuntimeDepsTag={runtimeDepsImageTag}") .SetPlatform(DockerPlatform) .SetTag(tag) .SetFile(dockerfile) - .SetPath(RootDirectory) - .SetPush(push) - .SetLoad(load); + .SetPath(RootDirectory); + + if (push) + { + // FD-492: Force a single, consistent OCI media type across the whole image + // manifest and disable default attestations. Without this, buildx can emit + // a manifest that mixes Docker and OCI layer media types (and an attestation + // index), which strict OCI clients such as Podman reject - in particular when + // the image is used as a base image (FROM ...). BUILDX_NO_DEFAULT_ATTESTATIONS + // is used (rather than --provenance=false) so the same switch applies to both + // `docker buildx build` here and `docker buildx bake` in the TeamCity Linux + // image build (see OctopusDeploy/TeamCity-Configuration). + // + // We also stamp the OCI image-spec annotations (org.opencontainers.image.*) + // onto both the image index and each platform manifest. The Dockerfile LABELs + // set the same metadata on the image *config*; annotations are the spec-preferred + // location that registries and OCI tooling read from the manifest/index. + // Keep these values in sync with the org.opencontainers.image.* LABELs in + // docker/kubernetes-agent-tentacle/Dockerfile. + var annotations = new Dictionary + { + ["org.opencontainers.image.title"] = "Octopus Deploy Kubernetes Agent Tentacle", + ["org.opencontainers.image.vendor"] = "Octopus Deploy", + ["org.opencontainers.image.url"] = "https://octopus.com", + ["org.opencontainers.image.source"] = "https://github.com/OctopusDeploy/OctopusTentacle", + ["org.opencontainers.image.licenses"] = "Apache-2.0", + ["org.opencontainers.image.description"] = "Octopus Kubernetes Agent Tentacle instance with auto-registration to Octopus Server", + ["org.opencontainers.image.version"] = FullSemVer, + ["org.opencontainers.image.created"] = buildDate, + }; + + // annotation-index.* lands on the image index, annotation.* on each platform manifest. + // Guard: annotation values are folded into the comma-separated buildx --output option + // list, so a comma in a value would corrupt it (the keys are fixed and comma-free). + var output = "type=image,oci-mediatypes=true,push=true"; + foreach (var (key, value) in annotations) + { + if (value.Contains(',')) + throw new InvalidOperationException( + $"OCI annotation '{key}' value must not contain a comma; it would break the buildx --output option list: '{value}'"); + + output += $",annotation-index.{key}={value},annotation.{key}={value}"; + } + + settings = settings + .SetOutput(output) + .AddProcessEnvironmentVariable("BUILDX_NO_DEFAULT_ATTESTATIONS", "1"); + } + else + { + settings = settings.SetLoad(load); + } if (includeDebugger) { diff --git a/docker/kubernetes-agent-tentacle/Dockerfile b/docker/kubernetes-agent-tentacle/Dockerfile index 19cf77842..4518755ba 100644 --- a/docker/kubernetes-agent-tentacle/Dockerfile +++ b/docker/kubernetes-agent-tentacle/Dockerfile @@ -115,13 +115,14 @@ ENV TentaclePollingProxyPassword="" ENTRYPOINT ["/scripts/configure-and-run.sh"] +# org.opencontainers.image.* metadata for the kubernetes-agent-tentacle image. +# Keep in sync with the OCI annotations set in build/Build.Pack.cs. LABEL \ - org.label-schema.schema-version="1.0" \ - org.label-schema.name="Octopus Deploy Kubernetes Agent Tentacle" \ - org.label-schema.vendor="Octopus Deploy" \ - org.label-schema.url="https://octopus.com" \ - org.label-schema.vcs-url="https://github.com/OctopusDeploy/OctopusTentacle" \ - org.label-schema.license="Apache" \ - org.label-schema.description="Octopus Kubernetes Agent Tentacle instance with auto-registration to Octopus Server" \ - org.label-schema.version=${BUILD_NUMBER} \ - org.label-schema.build-date=${BUILD_DATE} + org.opencontainers.image.title="Octopus Deploy Kubernetes Agent Tentacle" \ + org.opencontainers.image.vendor="Octopus Deploy" \ + org.opencontainers.image.url="https://octopus.com" \ + org.opencontainers.image.source="https://github.com/OctopusDeploy/OctopusTentacle" \ + org.opencontainers.image.licenses="Apache-2.0" \ + org.opencontainers.image.description="Octopus Kubernetes Agent Tentacle instance with auto-registration to Octopus Server" \ + org.opencontainers.image.version=${BUILD_NUMBER} \ + org.opencontainers.image.created=${BUILD_DATE} diff --git a/docker/kubernetes-agent-tentacle/dev/Dockerfile b/docker/kubernetes-agent-tentacle/dev/Dockerfile index 920babc24..7abc1127d 100644 --- a/docker/kubernetes-agent-tentacle/dev/Dockerfile +++ b/docker/kubernetes-agent-tentacle/dev/Dockerfile @@ -99,16 +99,17 @@ ENV TentaclePollingProxyPassword="" ENTRYPOINT [ "/dev-scripts/bootstrap.sh" ] +# org.opencontainers.image.* metadata for the dev/debug kubernetes tentacle image. +# Keep in sync with docker/kubernetes-agent-tentacle/Dockerfile. LABEL \ - org.label-schema.schema-version="1.0" \ - org.label-schema.name="Octopus Deploy Kubernetes Tentacle" \ - org.label-schema.vendor="Octopus Deploy" \ - org.label-schema.url="https://octopus.com" \ - org.label-schema.vcs-url="https://github.com/OctopusDeploy/OctopusTentacle" \ - org.label-schema.license="Apache" \ - org.label-schema.description="Octopus Kubernetes Tentacle instance with auto-registration to Octopus Server" \ - org.label-schema.version=${BUILD_NUMBER} \ - org.label-schema.build-date=${BUILD_DATE} + org.opencontainers.image.title="Octopus Deploy Kubernetes Tentacle" \ + org.opencontainers.image.vendor="Octopus Deploy" \ + org.opencontainers.image.url="https://octopus.com" \ + org.opencontainers.image.source="https://github.com/OctopusDeploy/OctopusTentacle" \ + org.opencontainers.image.licenses="Apache-2.0" \ + org.opencontainers.image.description="Octopus Kubernetes Tentacle instance with auto-registration to Octopus Server" \ + org.opencontainers.image.version=${BUILD_NUMBER} \ + org.opencontainers.image.created=${BUILD_DATE} # This installs the required tools, but there are versioning issues and it isn't working as expected diff --git a/docker/linux/Dockerfile b/docker/linux/Dockerfile index 75525462a..9e245c69e 100644 --- a/docker/linux/Dockerfile +++ b/docker/linux/Dockerfile @@ -82,13 +82,15 @@ VOLUME /var/lib/docker ENTRYPOINT [ "/scripts/configure-and-run.sh" ] +# org.opencontainers.image.* metadata for the published octopusdeploy/tentacle image. +# Keep in sync with docker/windows/Dockerfile and the index annotations in the TeamCity +# "Build: Docker manifest" step (OctopusDeploy/TeamCity-Configuration). LABEL \ - org.label-schema.schema-version="1.0" \ - org.label-schema.name="Octopus Deploy Tentacle" \ - org.label-schema.vendor="Octopus Deploy" \ - org.label-schema.url="https://octopus.com" \ - org.label-schema.vcs-url="https://github.com/OctopusDeploy/OctopusTentacle" \ - org.label-schema.license="Apache" \ - org.label-schema.description="Octopus Tentacle instance with auto-registration to Octopus Server" \ - org.label-schema.version=${BUILD_NUMBER} \ - org.label-schema.build-date=${BUILD_DATE} + org.opencontainers.image.title="Octopus Deploy Tentacle" \ + org.opencontainers.image.vendor="Octopus Deploy" \ + org.opencontainers.image.url="https://octopus.com" \ + org.opencontainers.image.source="https://github.com/OctopusDeploy/OctopusTentacle" \ + org.opencontainers.image.licenses="Apache-2.0" \ + org.opencontainers.image.description="Octopus Tentacle instance with auto-registration to Octopus Server" \ + org.opencontainers.image.version=${BUILD_NUMBER} \ + org.opencontainers.image.created=${BUILD_DATE} diff --git a/docker/windows/Dockerfile b/docker/windows/Dockerfile index 722f9a8da..621ba8ccc 100644 --- a/docker/windows/Dockerfile +++ b/docker/windows/Dockerfile @@ -7,16 +7,18 @@ ARG INSTALLATION_FOLDER="C:/Program Files/Octopus Deploy/Tentacle" ENV TentacleVersion ${BUILD_NUMBER} ENV OCTOPUS_RUNNING_IN_CONTAINER Y +# org.opencontainers.image.* metadata for the published octopusdeploy/tentacle image. +# Keep in sync with docker/linux/Dockerfile and the index annotations in the TeamCity +# "Build: Docker manifest" step (OctopusDeploy/TeamCity-Configuration). LABEL \ - org.label-schema.schema-version="1.0" \ - org.label-schema.name="Octopus Deploy Tentacle" \ - org.label-schema.vendor="Octopus Deploy" \ - org.label-schema.url="https://octopus.com" \ - org.label-schema.vcs-url="https://github.com/OctopusDeploy/OctopusTentacle" \ - org.label-schema.license="Apache" \ - org.label-schema.description="Octopus Tentacle instance with auto-registration to Octopus Server" \ - org.label-schema.version=${BUILD_NUMBER} \ - org.label-schema.build-date=${BUILD_DATE} + org.opencontainers.image.title="Octopus Deploy Tentacle" \ + org.opencontainers.image.vendor="Octopus Deploy" \ + org.opencontainers.image.url="https://octopus.com" \ + org.opencontainers.image.source="https://github.com/OctopusDeploy/OctopusTentacle" \ + org.opencontainers.image.licenses="Apache-2.0" \ + org.opencontainers.image.description="Octopus Tentacle instance with auto-registration to Octopus Server" \ + org.opencontainers.image.version=${BUILD_NUMBER} \ + org.opencontainers.image.created=${BUILD_DATE} EXPOSE 10933