From 41870fec7f11b5a6bb0fc8b25dfe4c27825a39b0 Mon Sep 17 00:00:00 2001 From: Yunare Maia Date: Wed, 23 Sep 2026 11:13:22 -0300 Subject: [PATCH] fix: skip docker:// references in github-actions PURL generation (#5302) closes #5299: docker:// references are OCI images, not GitHub repos. Returning empty string produces a package with no PURL, matching the treatment for local composite actions. Signed-off-by: Yunare Maia --- syft/pkg/cataloger/githubactions/package.go | 7 ++++++ .../githubactions/packageurl_test.go | 23 +++++++++++++++++++ .../workflow-with-docker-actions.yaml | 10 ++++++++ 3 files changed, 40 insertions(+) create mode 100644 syft/pkg/cataloger/githubactions/packageurl_test.go create mode 100644 syft/pkg/cataloger/githubactions/testdata/workflow-with-docker-actions.yaml diff --git a/syft/pkg/cataloger/githubactions/package.go b/syft/pkg/cataloger/githubactions/package.go index 179957510..49c5c83e4 100644 --- a/syft/pkg/cataloger/githubactions/package.go +++ b/syft/pkg/cataloger/githubactions/package.go @@ -88,6 +88,13 @@ func packageURL(name, version string) string { var subPath string var namespace string + // docker:// references are OCI images, not GitHub repos. + // They don't fit the pkg:github PURL shape, so skip them entirely + // (same treatment as local composite actions below). + if strings.HasPrefix(name, "docker:") { + return "" + } + fields := strings.SplitN(name, "/", 3) switch len(fields) { case 1: diff --git a/syft/pkg/cataloger/githubactions/packageurl_test.go b/syft/pkg/cataloger/githubactions/packageurl_test.go new file mode 100644 index 000000000..4174c2026 --- /dev/null +++ b/syft/pkg/cataloger/githubactions/packageurl_test.go @@ -0,0 +1,23 @@ +package githubactions + +import "testing" + +func Test_packageURL_skipsDockerPrefix(t *testing.T) { + // docker:// references should return empty PURL (not a valid pkg:github) + got := packageURL("docker://ghcr.io/sethvargo/ratchet:latest", "sha256:527e78e6d29a9ac306e843cf766afe0604a0b35633f16913d85dd522218e8ca1") + if got != "" { + t.Errorf("packageURL(digest-form) = %q, want empty string", got) + } + + got = packageURL("docker://ghcr.io/some-org/some-action", "v1") + if got != "" { + t.Errorf("packageURL(tag-form) = %q, want empty string", got) + } + + // Sanity: regular github actions still work + got = packageURL("actions/checkout", "v4") + want := "pkg:github/actions/checkout@v4" + if got != want { + t.Errorf("packageURL(regular) = %q, want %q", got, want) + } +} diff --git a/syft/pkg/cataloger/githubactions/testdata/workflow-with-docker-actions.yaml b/syft/pkg/cataloger/githubactions/testdata/workflow-with-docker-actions.yaml new file mode 100644 index 000000000..c33a3d54b --- /dev/null +++ b/syft/pkg/cataloger/githubactions/testdata/workflow-with-docker-actions.yaml @@ -0,0 +1,10 @@ +name: "Docker Actions Test" +on: [push] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: docker://ghcr.io/sethvargo/ratchet:latest@sha256:527e78e6d29a9ac306e843cf766afe0604a0b35633f16913d85dd522218e8ca1 + - uses: docker://ghcr.io/some-org/some-action@v1 + - uses: actions/setup-go@v5