diff --git a/pkg/dockerfile/extract.go b/pkg/dockerfile/extract.go index d90fd229c65..b71cea811ec 100644 --- a/pkg/dockerfile/extract.go +++ b/pkg/dockerfile/extract.go @@ -14,6 +14,9 @@ import ( // RegistryRegex matches registry references to registry.ci.openshift.org or quay-proxy.ci.openshift.org var RegistryRegex = regexp.MustCompile(`(registry\.(?:svc\.)?ci\.openshift\.org|quay-proxy\.ci\.openshift\.org)/[^\s\\]+`) +// dockerfileLineContinuation matches Dockerfile backslash line continuations. +var dockerfileLineContinuation = regexp.MustCompile(`\\\r?\n[ \t]*`) + // OrgRepoTag represents a parsed image reference type OrgRepoTag struct { Org, Repo, Tag string @@ -23,37 +26,44 @@ func (ort OrgRepoTag) String() string { return ort.Org + "_" + ort.Repo + "_" + ort.Tag } -// ExtractRegistryReferences finds all registry.ci.openshift.org and quay-proxy.ci.openshift.org references in the Dockerfile +// ExtractRegistryReferences finds registry.ci.openshift.org and quay-proxy.ci.openshift.org references in +// Dockerfile FROM, COPY --from=, and RUN instructions (e.g. podman pull). func ExtractRegistryReferences(dockerfile []byte, from api.PipelineImageStreamTagReference) []string { + dockerfile = dockerfileLineContinuation.ReplaceAll(dockerfile, []byte(" ")) + var refs []string seen := sets.Set[string]{} - lastFromRef := "" + var lastFromLineRegistryRef string for _, line := range bytes.Split(dockerfile, []byte("\n")) { upper := bytes.ToUpper(line) - if !bytes.Contains(upper, []byte("FROM")) && !bytes.Contains(upper, []byte("COPY")) { + if !bytes.Contains(upper, []byte("FROM")) && !bytes.Contains(upper, []byte("COPY")) && !bytes.Contains(upper, []byte("RUN")) { continue } + if bytes.HasPrefix(upper, []byte("FROM")) { + lastFromLineRegistryRef = "" + if match := RegistryRegex.Find(line); match != nil { + lastFromLineRegistryRef = string(match) + } + } + match := RegistryRegex.Find(line) if match == nil { continue } ref := string(match) - if bytes.HasPrefix(upper, []byte("FROM")) { - lastFromRef = ref - } if !seen.Has(ref) { refs = append(refs, ref) seen.Insert(ref) } } - if from != "" { - // If from is specified, remove the last detected FROM ref, it will be replaced + if from != "" && lastFromLineRegistryRef != "" { + // images[].from replaces the final Dockerfile stage; exclude only that stage's registry.ci reference var newRefs []string for _, ref := range refs { - if ref != lastFromRef { + if ref != lastFromLineRegistryRef { newRefs = append(newRefs, ref) } } diff --git a/pkg/dockerfile/inputs_test.go b/pkg/dockerfile/inputs_test.go index 9110fbde9ff..2e2c35fdccc 100644 --- a/pkg/dockerfile/inputs_test.go +++ b/pkg/dockerfile/inputs_test.go @@ -165,6 +165,50 @@ RUN echo "hello" }, }, }, + { + name: "RUN podman pull registry.ci reference", + dockerfile: `FROM registry.access.redhat.com/ubi9/ubi-minimal:latest +RUN podman pull registry.ci.openshift.org/ocp/4.19:tools && cp bin/tool /usr/bin/tool +`, + expected: map[string]api.ImageStreamTagReference{ + "ocp_4.19_tools": { + Namespace: "ocp", + Name: "4.19", + Tag: "tools", + As: "registry.ci.openshift.org/ocp/4.19:tools", + }, + }, + }, + { + name: "RUN podman pull with line continuation", + dockerfile: `FROM registry.access.redhat.com/ubi9/ubi-minimal:latest +RUN podman pull \ + registry.ci.openshift.org/ocp/4.19:tools && cp bin/tool /usr/bin/tool +`, + expected: map[string]api.ImageStreamTagReference{ + "ocp_4.19_tools": { + Namespace: "ocp", + Name: "4.19", + Tag: "tools", + As: "registry.ci.openshift.org/ocp/4.19:tools", + }, + }, + }, + { + name: "from: ubi with external final stage keeps builder registry.ci FROM", + dockerfile: `FROM registry.ci.openshift.org/ocp/builder:rhel-9-golang-1.22-openshift-4.18 AS builder +FROM registry.access.redhat.com/ubi9/ubi-minimal:latest +`, + from: "ubi", + expected: map[string]api.ImageStreamTagReference{ + "ocp_builder_rhel-9-golang-1.22-openshift-4.18": { + Namespace: "ocp", + Name: "builder", + Tag: "rhel-9-golang-1.22-openshift-4.18", + As: "registry.ci.openshift.org/ocp/builder:rhel-9-golang-1.22-openshift-4.18", + }, + }, + }, { name: "from: is specified - should exclude the last detected FROM ref with COPY", dockerfile: `FROM registry.ci.openshift.org/ocp/4.18:base AS builder