feat(report): add image reference to report metadata (#9729)

This commit is contained in:
Teppei Fukuda
2025-10-31 11:26:39 +04:00
committed by GitHub
parent 29f0347965
commit d020f2690e
53 changed files with 121 additions and 83 deletions

View File

@@ -27,6 +27,7 @@ import (
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
"github.com/aquasecurity/trivy/internal/testutil"
"github.com/aquasecurity/trivy/pkg/types"
)
@@ -249,7 +250,7 @@ func TestRegistry(t *testing.T) {
runTest(t, osArgs, tt.golden, types.FormatJSON, runOptions{
wantErr: tt.wantErr,
fakeUUID: "3ff14136-e09f-4df9-80ea-%012d",
override: overrideFuncs(overrideUID, func(_ *testing.T, want, got *types.Report) {
override: overrideFuncs(overrideUID, func(t *testing.T, want, got *types.Report) {
// Exclude ArtifactID from comparison because registry tests use random ports
// (e.g., localhost:54321/alpine:3.10), which causes RepoTags and the calculated
// Artifact ID to vary on each test run.
@@ -258,6 +259,7 @@ func TestRegistry(t *testing.T) {
want.ArtifactName = s
want.Metadata.RepoTags = []string{s}
want.Metadata.Reference = testutil.MustParseReference(t, s)
for i := range want.Results {
want.Results[i].Target = fmt.Sprintf("%s (%s)", s, tt.os)
}

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:almalinux-8"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:almalinux-8",
"ImageConfig": {
"architecture": "amd64",
"container": "a467f67a48d469e1975b7414f33f2cf87121d4cc59d2ee029ea58e6b81774769",

View File

@@ -19,6 +19,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:alpine-310"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:alpine-310",
"ImageConfig": {
"architecture": "amd64",
"container": "0a80155a31551fcc1a36fccbbda79fcd3f0b1c7d270653d00310e6e2217c57e6",

View File

@@ -19,6 +19,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:alpine-39"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:alpine-39",
"ImageConfig": {
"architecture": "amd64",
"container": "c10d36fa368a7ea673683682666758adf35efe98e10989505f4f566b5b18538f",

View File

@@ -19,6 +19,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:alpine-39"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:alpine-39",
"ImageConfig": {
"architecture": "amd64",
"container": "c10d36fa368a7ea673683682666758adf35efe98e10989505f4f566b5b18538f",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:alpine-39"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:alpine-39",
"ImageConfig": {
"architecture": "amd64",
"container": "c10d36fa368a7ea673683682666758adf35efe98e10989505f4f566b5b18538f",

View File

@@ -19,6 +19,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:alpine-39"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:alpine-39",
"ImageConfig": {
"architecture": "amd64",
"container": "c10d36fa368a7ea673683682666758adf35efe98e10989505f4f566b5b18538f",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:alpine-distroless"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:alpine-distroless",
"ImageConfig": {
"architecture": "amd64",
"author": "github.com/chainguard-dev/apko",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:amazon-1"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:amazon-1",
"ImageConfig": {
"architecture": "amd64",
"container": "ef1b126795001e9b4bdc14a01180e4d8146282d279f53e05adfaa8195ecda20e",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:amazon-2"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:amazon-2",
"ImageConfig": {
"architecture": "amd64",
"container": "e020a5508b9f809b29659128692cd634e3d4fba3f2c13d2029d797317b5c3a56",

View File

@@ -15,6 +15,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:busybox-with-lockfile"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:busybox-with-lockfile",
"ImageConfig": {
"architecture": "amd64",
"created": "2022-06-07T04:24:40.230164Z",

View File

@@ -19,6 +19,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:centos-6"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:centos-6",
"ImageConfig": {
"architecture": "amd64",
"author": "https://github.com/CentOS/sig-cloud-instance-images",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:centos-7"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:centos-7",
"ImageConfig": {
"architecture": "amd64",
"container": "cc6043a787f6d1c7ae3e121ebdf1c4478186336aa7274871780a0a7bcc3a061a",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:centos-7"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:centos-7",
"ImageConfig": {
"architecture": "amd64",
"container": "cc6043a787f6d1c7ae3e121ebdf1c4478186336aa7274871780a0a7bcc3a061a",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:centos-7"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:centos-7",
"ImageConfig": {
"architecture": "amd64",
"container": "cc6043a787f6d1c7ae3e121ebdf1c4478186336aa7274871780a0a7bcc3a061a",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:debian-buster"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:debian-buster",
"ImageConfig": {
"architecture": "amd64",
"container": "cbb6a20ddb7dedfeee41aeb21e9780f14afbb0f47a6b1ffa514a1822f45d0a51",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:debian-buster"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:debian-buster",
"ImageConfig": {
"architecture": "amd64",
"container": "cbb6a20ddb7dedfeee41aeb21e9780f14afbb0f47a6b1ffa514a1822f45d0a51",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:debian-stretch"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:debian-stretch",
"ImageConfig": {
"architecture": "amd64",
"container": "957bc0b73d29f0e1030fec9c63f81d3e81baa610cffcc9c574b14fee6d1821ae",

View File

@@ -19,6 +19,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:distroless-base"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:distroless-base",
"ImageConfig": {
"architecture": "amd64",
"author": "Bazel",

View File

@@ -21,6 +21,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:distroless-python27"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:distroless-python27",
"ImageConfig": {
"architecture": "amd64",
"author": "Bazel",

View File

@@ -1 +1 @@
{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2N5Y2xvbmVkeC5vcmcvYm9tIiwic3ViamVjdCI6W3sibmFtZSI6ImluZGV4LmRvY2tlci5pby9saWJyYXJ5L2NlbnRvcyIsImRpZ2VzdCI6eyJzaGEyNTYiOiJiZTY1ZjQ4OGI3NzY0YWQzNjM4ZjIzNmI3YjUxNWIzNjc4MzY5YTUxMjRjNDdiOGQzMjkxNmQ2NDg3NDE4ZWE0In19XSwicHJlZGljYXRlIjp7ImJvbUZvcm1hdCI6IkN5Y2xvbmVEWCIsInNwZWNWZXJzaW9uIjoiMS40Iiwic2VyaWFsTnVtYmVyIjoidXJuOnV1aWQ6MTQ1NWMwMmQtNjRjYS00NTNlLWE1ZGYtZGRmYjcwYTdjODA0IiwidmVyc2lvbiI6MSwibWV0YWRhdGEiOnsidGltZXN0YW1wIjoiMjAyMi0wNi0xNFQxNTowODo0OCswMDowMCIsInRvb2xzIjpbeyJ2ZW5kb3IiOiJhcXVhc2VjdXJpdHkiLCJuYW1lIjoidHJpdnkiLCJ2ZXJzaW9uIjoiZGV2In1dLCJjb21wb25lbnQiOnsiYm9tLXJlZiI6ImQwZDQxZTMwLTk2NTAtNDg5ZC05NDhkLTQyNWZmMmVkNjNkMiIsInR5cGUiOiJjb250YWluZXIiLCJuYW1lIjoiaW50ZWdyYXRpb24vdGVzdGRhdGEvZml4dHVyZXMvaW1hZ2VzL2NlbnRvcy03LnRhci5neiIsInByb3BlcnRpZXMiOlt7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U2NoZW1hVmVyc2lvbiIsInZhbHVlIjoiMiJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpJbWFnZUlEIiwidmFsdWUiOiJzaGEyNTY6ZjFjYjdjN2Q1OGI3M2VhYzg1OWMzOTU4ODJlZWM0OWQ1MDY1MTI0NGUzNDJjZDZjNjhhNWM3ODA5Nzg1ZjQyNyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpEaWZmSUQiLCJ2YWx1ZSI6InNoYTI1Njo4OTE2OWQ4N2RiZTJiNzJiYTQyYmZiYjM1NzljOTU3MzIyYmFjYTI4ZTAzYTFlNTU4MDc2NTQyYTFjMWIyYjRhIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlJlcG9UYWciLCJ2YWx1ZSI6ImdoY3IuaW8vYXF1YXNlY3VyaXR5L3RyaXZ5LXRlc3QtaW1hZ2VzOmNlbnRvcy03In1dfX0sImNvbXBvbmVudHMiOlt7ImJvbS1yZWYiOiJwa2c6cnBtL2NlbnRvcy9iYXNoQDQuMi40Ni0zMS5lbDc/YXJjaD14ODZfNjQmZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsInR5cGUiOiJsaWJyYXJ5IiwibmFtZSI6ImJhc2giLCJ2ZXJzaW9uIjoiNC4yLjQ2LTMxLmVsNyIsImxpY2Vuc2VzIjpbeyJleHByZXNzaW9uIjoiR1BMdjMrIn1dLCJwdXJsIjoicGtnOnJwbS9jZW50b3MvYmFzaEA0LjIuNDYtMzEuZWw3P2FyY2g9eDg2XzY0JmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJwcm9wZXJ0aWVzIjpbeyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlBrZ0lEIiwidmFsdWUiOiJiYXNoQDQuMi40Ni0zMS5lbDcueDg2XzY0In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY05hbWUiLCJ2YWx1ZSI6ImJhc2gifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjVmVyc2lvbiIsInZhbHVlIjoiNC4yLjQ2In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY1JlbGVhc2UiLCJ2YWx1ZSI6IjMxLmVsNyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpMYXllckRpZ2VzdCIsInZhbHVlIjoic2hhMjU2OmFjOTIwODIwN2FkYWFjM2E0OGU1NGE0ZGM2YjQ5YzY5ZTc4YzMwNzJkMmIzYWRkN2VmZGFiZjgxNGRiMjEzM2IifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6TGF5ZXJEaWZmSUQiLCJ2YWx1ZSI6InNoYTI1Njo4OTE2OWQ4N2RiZTJiNzJiYTQyYmZiYjM1NzljOTU3MzIyYmFjYTI4ZTAzYTFlNTU4MDc2NTQyYTFjMWIyYjRhIn1dfSx7ImJvbS1yZWYiOiJwa2c6cnBtL2NlbnRvcy9vcGVuc3NsLWxpYnNAMS4wLjJrLTE2LmVsNz9hcmNoPXg4Nl82NCZlcG9jaD0xJmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJ0eXBlIjoibGlicmFyeSIsIm5hbWUiOiJvcGVuc3NsLWxpYnMiLCJ2ZXJzaW9uIjoiMS4wLjJrLTE2LmVsNyIsImxpY2Vuc2VzIjpbeyJleHByZXNzaW9uIjoiT3BlblNTTCJ9XSwicHVybCI6InBrZzpycG0vY2VudG9zL29wZW5zc2wtbGlic0AxLjAuMmstMTYuZWw3P2FyY2g9eDg2XzY0JmVwb2NoPTEmZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsInByb3BlcnRpZXMiOlt7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6UGtnSUQiLCJ2YWx1ZSI6Im9wZW5zc2wtbGlic0AxLjAuMmstMTYuZWw3Lng4Nl82NCJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNOYW1lIiwidmFsdWUiOiJvcGVuc3NsIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY1ZlcnNpb24iLCJ2YWx1ZSI6IjEuMC4yayJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNSZWxlYXNlIiwidmFsdWUiOiIxNi5lbDcifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjRXBvY2giLCJ2YWx1ZSI6IjEifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6TGF5ZXJEaWdlc3QiLCJ2YWx1ZSI6InNoYTI1NjphYzkyMDgyMDdhZGFhYzNhNDhlNTRhNGRjNmI0OWM2OWU3OGMzMDcyZDJiM2FkZDdlZmRhYmY4MTRkYjIxMzNiIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OkxheWVyRGlmZklEIiwidmFsdWUiOiJzaGEyNTY6ODkxNjlkODdkYmUyYjcyYmE0MmJmYmIzNTc5Yzk1NzMyMmJhY2EyOGUwM2ExZTU1ODA3NjU0MmExYzFiMmI0YSJ9XX0seyJib20tcmVmIjoiMDE3NWY3MzItZGY5ZC00YmI4LTlmNTYtODcwODk4ZTNmZjg5IiwidHlwZSI6Im9wZXJhdGluZy1zeXN0ZW0iLCJuYW1lIjoiY2VudG9zIiwidmVyc2lvbiI6IjcuNi4xODEwIiwicHJvcGVydGllcyI6W3sibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpUeXBlIiwidmFsdWUiOiJjZW50b3MifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6Q2xhc3MiLCJ2YWx1ZSI6Im9zLXBrZ3MifV19XSwiZGVwZW5kZW5jaWVzIjpbeyJyZWYiOiIwMTc1ZjczMi1kZjlkLTRiYjgtOWY1Ni04NzA4OThlM2ZmODkiLCJkZXBlbmRzT24iOlsicGtnOnJwbS9jZW50b3MvYmFzaEA0LjIuNDYtMzEuZWw3P2FyY2g9eDg2XzY0JmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJwa2c6cnBtL2NlbnRvcy9vcGVuc3NsLWxpYnNAMS4wLjJrLTE2LmVsNz9hcmNoPXg4Nl82NCZlcG9jaD0xJmRpc3Rybz1jZW50b3MtNy42LjE4MTAiXX0seyJyZWYiOiJkMGQ0MWUzMC05NjUwLTQ4OWQtOTQ4ZC00MjVmZjJlZDYzZDIiLCJkZXBlbmRzT24iOlsiMDE3NWY3MzItZGY5ZC00YmI4LTlmNTYtODcwODk4ZTNmZjg5Il19XX19Cg==","signatures":[{"keyid":"","sig":"MEUCIQCtj78dipe+yzdlIsmwjn9QeaBTAPQacwIJAWfnrtp7FwIgcViOUgPA0WFYjimrIl7vbygdSpduM+ZzY3cqrDciH1U="}]}
{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2N5Y2xvbmVkeC5vcmcvYm9tIiwic3ViamVjdCI6W3sibmFtZSI6ImluZGV4LmRvY2tlci5pby9saWJyYXJ5L2NlbnRvcyIsImRpZ2VzdCI6eyJzaGEyNTYiOiJiZTY1ZjQ4OGI3NzY0YWQzNjM4ZjIzNmI3YjUxNWIzNjc4MzY5YTUxMjRjNDdiOGQzMjkxNmQ2NDg3NDE4ZWE0In19XSwicHJlZGljYXRlIjp7ImJvbUZvcm1hdCI6IkN5Y2xvbmVEWCIsInNwZWNWZXJzaW9uIjoiMS40Iiwic2VyaWFsTnVtYmVyIjoidXJuOnV1aWQ6MTQ1NWMwMmQtNjRjYS00NTNlLWE1ZGYtZGRmYjcwYTdjODA0IiwidmVyc2lvbiI6MSwibWV0YWRhdGEiOnsidGltZXN0YW1wIjoiMjAyMi0wNi0xNFQxNTowODo0OCswMDowMCIsInRvb2xzIjpbeyJ2ZW5kb3IiOiJhcXVhc2VjdXJpdHkiLCJuYW1lIjoidHJpdnkiLCJ2ZXJzaW9uIjoiZGV2In1dLCJjb21wb25lbnQiOnsiYm9tLXJlZiI6ImQwZDQxZTMwLTk2NTAtNDg5ZC05NDhkLTQyNWZmMmVkNjNkMiIsInR5cGUiOiJjb250YWluZXIiLCJuYW1lIjoiaW50ZWdyYXRpb24vdGVzdGRhdGEvZml4dHVyZXMvaW1hZ2VzL2NlbnRvcy03LnRhci5neiIsInByb3BlcnRpZXMiOlt7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U2NoZW1hVmVyc2lvbiIsInZhbHVlIjoiMiJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpJbWFnZUlEIiwidmFsdWUiOiJzaGEyNTY6ZjFjYjdjN2Q1OGI3M2VhYzg1OWMzOTU4ODJlZWM0OWQ1MDY1MTI0NGUzNDJjZDZjNjhhNWM3ODA5Nzg1ZjQyNyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpEaWZmSUQiLCJ2YWx1ZSI6InNoYTI1Njo4OTE2OWQ4N2RiZTJiNzJiYTQyYmZiYjM1NzljOTU3MzIyYmFjYTI4ZTAzYTFlNTU4MDc2NTQyYTFjMWIyYjRhIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlJlcG9UYWciLCJ2YWx1ZSI6ImdoY3IuaW8vYXF1YXNlY3VyaXR5L3RyaXZ5LXRlc3QtaW1hZ2VzOmNlbnRvcy03In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlJlZmVyZW5jZSIsInZhbHVlIjoiZ2hjci5pby9hcXVhc2VjdXJpdHkvdHJpdnktdGVzdC1pbWFnZXM6Y2VudG9zLTcifV19fSwiY29tcG9uZW50cyI6W3siYm9tLXJlZiI6InBrZzpycG0vY2VudG9zL2Jhc2hANC4yLjQ2LTMxLmVsNz9hcmNoPXg4Nl82NCZkaXN0cm89Y2VudG9zLTcuNi4xODEwIiwidHlwZSI6ImxpYnJhcnkiLCJuYW1lIjoiYmFzaCIsInZlcnNpb24iOiI0LjIuNDYtMzEuZWw3IiwibGljZW5zZXMiOlt7ImV4cHJlc3Npb24iOiJHUEx2MysifV0sInB1cmwiOiJwa2c6cnBtL2NlbnRvcy9iYXNoQDQuMi40Ni0zMS5lbDc/YXJjaD14ODZfNjQmZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsInByb3BlcnRpZXMiOlt7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6UGtnSUQiLCJ2YWx1ZSI6ImJhc2hANC4yLjQ2LTMxLmVsNy54ODZfNjQifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjTmFtZSIsInZhbHVlIjoiYmFzaCJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNWZXJzaW9uIiwidmFsdWUiOiI0LjIuNDYifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjUmVsZWFzZSIsInZhbHVlIjoiMzEuZWw3In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OkxheWVyRGlnZXN0IiwidmFsdWUiOiJzaGEyNTY6YWM5MjA4MjA3YWRhYWMzYTQ4ZTU0YTRkYzZiNDljNjllNzhjMzA3MmQyYjNhZGQ3ZWZkYWJmODE0ZGIyMTMzYiJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpMYXllckRpZmZJRCIsInZhbHVlIjoic2hhMjU2Ojg5MTY5ZDg3ZGJlMmI3MmJhNDJiZmJiMzU3OWM5NTczMjJiYWNhMjhlMDNhMWU1NTgwNzY1NDJhMWMxYjJiNGEifV19LHsiYm9tLXJlZiI6InBrZzpycG0vY2VudG9zL29wZW5zc2wtbGlic0AxLjAuMmstMTYuZWw3P2FyY2g9eDg2XzY0JmVwb2NoPTEmZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsInR5cGUiOiJsaWJyYXJ5IiwibmFtZSI6Im9wZW5zc2wtbGlicyIsInZlcnNpb24iOiIxLjAuMmstMTYuZWw3IiwibGljZW5zZXMiOlt7ImV4cHJlc3Npb24iOiJPcGVuU1NMIn1dLCJwdXJsIjoicGtnOnJwbS9jZW50b3Mvb3BlbnNzbC1saWJzQDEuMC4yay0xNi5lbDc/YXJjaD14ODZfNjQmZXBvY2g9MSZkaXN0cm89Y2VudG9zLTcuNi4xODEwIiwicHJvcGVydGllcyI6W3sibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpQa2dJRCIsInZhbHVlIjoib3BlbnNzbC1saWJzQDEuMC4yay0xNi5lbDcueDg2XzY0In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY05hbWUiLCJ2YWx1ZSI6Im9wZW5zc2wifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjVmVyc2lvbiIsInZhbHVlIjoiMS4wLjJrIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY1JlbGVhc2UiLCJ2YWx1ZSI6IjE2LmVsNyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNFcG9jaCIsInZhbHVlIjoiMSJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpMYXllckRpZ2VzdCIsInZhbHVlIjoic2hhMjU2OmFjOTIwODIwN2FkYWFjM2E0OGU1NGE0ZGM2YjQ5YzY5ZTc4YzMwNzJkMmIzYWRkN2VmZGFiZjgxNGRiMjEzM2IifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6TGF5ZXJEaWZmSUQiLCJ2YWx1ZSI6InNoYTI1Njo4OTE2OWQ4N2RiZTJiNzJiYTQyYmZiYjM1NzljOTU3MzIyYmFjYTI4ZTAzYTFlNTU4MDc2NTQyYTFjMWIyYjRhIn1dfSx7ImJvbS1yZWYiOiIwMTc1ZjczMi1kZjlkLTRiYjgtOWY1Ni04NzA4OThlM2ZmODkiLCJ0eXBlIjoib3BlcmF0aW5nLXN5c3RlbSIsIm5hbWUiOiJjZW50b3MiLCJ2ZXJzaW9uIjoiNy42LjE4MTAiLCJwcm9wZXJ0aWVzIjpbeyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlR5cGUiLCJ2YWx1ZSI6ImNlbnRvcyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpDbGFzcyIsInZhbHVlIjoib3MtcGtncyJ9XX1dLCJkZXBlbmRlbmNpZXMiOlt7InJlZiI6IjAxNzVmNzMyLWRmOWQtNGJiOC05ZjU2LTg3MDg5OGUzZmY4OSIsImRlcGVuZHNPbiI6WyJwa2c6cnBtL2NlbnRvcy9iYXNoQDQuMi40Ni0zMS5lbDc/YXJjaD14ODZfNjQmZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsInBrZzpycG0vY2VudG9zL29wZW5zc2wtbGlic0AxLjAuMmstMTYuZWw3P2FyY2g9eDg2XzY0JmVwb2NoPTEmZGlzdHJvPWNlbnRvcy03LjYuMTgxMCJdfSx7InJlZiI6ImQwZDQxZTMwLTk2NTAtNDg5ZC05NDhkLTQyNWZmMmVkNjNkMiIsImRlcGVuZHNPbiI6WyIwMTc1ZjczMi1kZjlkLTRiYjgtOWY1Ni04NzA4OThlM2ZmODkiXX1dfX0K","signatures":[{"keyid":"","sig":"MEUCIQCtj78dipe+yzdlIsmwjn9QeaBTAPQacwIJAWfnrtp7FwIgcViOUgPA0WFYjimrIl7vbygdSpduM+ZzY3cqrDciH1U="}]}

View File

@@ -32,6 +32,10 @@
{
"name": "aquasecurity:trivy:RepoTag",
"value": "ghcr.io/aquasecurity/trivy-test-images:centos-7"
},
{
"name": "aquasecurity:trivy:Reference",
"value": "ghcr.io/aquasecurity/trivy-test-images:centos-7"
}
]
}

View File

@@ -17,7 +17,8 @@
"SchemaVersion: 2",
"ImageID: sha256:f1cb7c7d58b73eac859c395882eec49d50651244e342cd6c68a5c7809785f427",
"DiffID: sha256:89169d87dbe2b72ba42bfbb3579c957322baca28e03a1e558076542a1c1b2b4a",
"RepoTag: ghcr.io/aquasecurity/trivy-test-images:centos-7"
"RepoTag: ghcr.io/aquasecurity/trivy-test-images:centos-7",
"Reference: ghcr.io/aquasecurity/trivy-test-images:centos-7"
],
"filesAnalyzed": false,
"name": "integration/testdata/fixtures/images/centos-7.tar.gz"

View File

@@ -16,6 +16,7 @@ PackageAttributionText: SchemaVersion: 2
PackageAttributionText: ImageID: sha256:f1cb7c7d58b73eac859c395882eec49d50651244e342cd6c68a5c7809785f427
PackageAttributionText: DiffID: sha256:89169d87dbe2b72ba42bfbb3579c957322baca28e03a1e558076542a1c1b2b4a
PackageAttributionText: RepoTag: ghcr.io/aquasecurity/trivy-test-images:centos-7
PackageAttributionText: Reference: ghcr.io/aquasecurity/trivy-test-images:centos-7
##### Package: centos

View File

@@ -23,6 +23,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:fluentd-multiple-lockfiles"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:fluentd-multiple-lockfiles",
"ImageConfig": {
"architecture": "amd64",
"container": "232f3fc7ddffd71dc3ff52c6c0c3a5feea2f51acffd9b53850a8fc6f1a15319a",

View File

@@ -52,6 +52,10 @@
"name": "aquasecurity:trivy:ImageID",
"value": "sha256:5a992077baba51b97f27591a10d54d2f2723dc9c81a3fe419e261023f2554933"
},
{
"name": "aquasecurity:trivy:Reference",
"value": "ghcr.io/aquasecurity/trivy-test-images:fluentd-multiple-lockfiles"
},
{
"name": "aquasecurity:trivy:RepoTag",
"value": "ghcr.io/aquasecurity/trivy-test-images:fluentd-multiple-lockfiles"

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:mariner-1.0"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:mariner-1.0",
"ImageConfig": {
"architecture": "amd64",
"created": "2022-01-27T01:19:38.526301656Z",

View File

@@ -19,6 +19,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:opensuse-leap-151"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:opensuse-leap-151",
"ImageConfig": {
"architecture": "amd64",
"author": "Fabian Vogt \u003cfvogt@suse.com\u003e",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:opensuse-tumbleweed"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:opensuse-tumbleweed",
"ImageConfig": {
"architecture": "amd64",
"author": "Fabian Vogt \u003cfvogt@suse.com\u003e",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:oraclelinux-8"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:oraclelinux-8",
"ImageConfig": {
"architecture": "amd64",
"author": "Oracle Linux Product Team \u003col-ovm-info_ww@oracle.com\u003e",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:photon-30"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:photon-30",
"ImageConfig": {
"architecture": "amd64",
"container": "ed27e7f1fbd8ef9d3ea89947f682907e9a65a8e51bbe2e0eba60db6e69213848",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:rockylinux-8"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:rockylinux-8",
"ImageConfig": {
"architecture": "amd64",
"container": "16458df10693f731fae0492f791a5e4b725245c35cf28c7fca00982219d7bdf3",

View File

@@ -18,6 +18,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:sle-micro-rancher-5.4_ndb"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:sle-micro-rancher-5.4_ndb",
"ImageConfig": {
"architecture": "amd64",
"author": "SUSE LLC (https://www.suse.com/)",

View File

@@ -26,6 +26,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:spring4shell-jre11"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:spring4shell-jre11",
"ImageConfig": {
"architecture": "amd64",
"created": "2022-06-07T03:41:13.228952Z",

View File

@@ -26,6 +26,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:spring4shell-jre8"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:spring4shell-jre8",
"ImageConfig": {
"architecture": "amd64",
"created": "2022-06-06T13:51:57.120019Z",

View File

@@ -19,6 +19,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:ubi-7"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:ubi-7",
"ImageConfig": {
"architecture": "amd64",
"created": "2019-09-02T12:56:43.939095Z",

View File

@@ -19,6 +19,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:ubi-7"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:ubi-7",
"ImageConfig": {
"architecture": "amd64",
"created": "2019-09-02T12:56:43.939095Z",

View File

@@ -21,6 +21,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:ubuntu-1804"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:ubuntu-1804",
"ImageConfig": {
"architecture": "amd64",
"container": "41b694b9b42f9c5ef7fb40c24272927a727a6d6cb8120bb3eae5849ceb9bee77",

View File

@@ -21,6 +21,7 @@
"RepoTags": [
"ghcr.io/aquasecurity/trivy-test-images:ubuntu-1804"
],
"Reference": "ghcr.io/aquasecurity/trivy-test-images:ubuntu-1804",
"ImageConfig": {
"architecture": "amd64",
"container": "41b694b9b42f9c5ef7fb40c24272927a727a6d6cb8120bb3eae5849ceb9bee77",

View File

@@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/fanal/image"
"github.com/aquasecurity/trivy/pkg/fanal/image/name"
)
var (
@@ -72,9 +72,9 @@ func imageName(img, subpath, tag, digest string) string {
}
// MustParseReference parses a string into a Reference and fails the test if there's an error
func MustParseReference(t *testing.T, s string) image.Reference {
func MustParseReference(t *testing.T, s string) name.Reference {
t.Helper()
ref, err := image.ParseReference(s)
ref, err := name.ParseReference(s)
require.NoError(t, err)
return ref
}

View File

@@ -8,7 +8,7 @@ import (
"github.com/google/go-containerregistry/pkg/v1"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/image"
"github.com/aquasecurity/trivy/pkg/fanal/image/name"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/walker"
"github.com/aquasecurity/trivy/pkg/misconf"
@@ -104,7 +104,7 @@ type ImageMetadata struct {
DiffIDs []string // uncompressed layer IDs
RepoTags []string
RepoDigests []string
Reference image.Reference // image reference matching the artifact name
Reference name.Reference // image reference matching the artifact name
ConfigFile v1.ConfigFile
}

View File

@@ -1,7 +1,6 @@
package image
import (
"cmp"
"context"
"errors"
"fmt"
@@ -13,7 +12,6 @@ import (
"strings"
"github.com/docker/go-units"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/samber/lo"
"golang.org/x/sync/errgroup"
@@ -24,6 +22,7 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/fanal/handler"
"github.com/aquasecurity/trivy/pkg/fanal/image"
"github.com/aquasecurity/trivy/pkg/fanal/image/name"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/walker"
"github.com/aquasecurity/trivy/pkg/log"
@@ -173,48 +172,33 @@ func (a Artifact) Clean(_ artifact.Reference) error {
}
// findMatchingReference finds a RepoTag or RepoDigest that matches the artifact name
func (a Artifact) findMatchingReference(artifactName string, repoTags, repoDigests []string) image.Reference {
func (a Artifact) findMatchingReference(artifactName string, repoTags, repoDigests []string) name.Reference {
// Convert strings to typed references
parsedTags := a.parseRepoTags(repoTags)
parsedDigests := a.parseRepoDigests(repoDigests)
ref := a.findMatchingRepoReference(artifactName, parsedTags, parsedDigests)
return image.NewReference(ref)
references := a.parseImageReferences(slices.Concat(repoTags, repoDigests))
return a.findMatchingRepoReference(artifactName, references)
}
// parseRepoTags parses repo tags into name.Tag
func (a Artifact) parseRepoTags(repoTags []string) []name.Tag {
return lo.FilterMap(repoTags, func(tagStr string, _ int) (name.Tag, bool) {
tag, err := name.NewTag(tagStr)
// parseImageReferences parses repo tags/digests into name.Reference
func (a Artifact) parseImageReferences(references []string) []name.Reference {
return lo.FilterMap(references, func(ref string, _ int) (name.Reference, bool) {
tag, err := name.ParseReference(ref)
if err != nil {
a.logger.Debug("Failed to parse repo tag", log.String("tag", tagStr), log.Err(err))
return name.Tag{}, false
a.logger.Debug("Failed to parse repo tag/digest", log.String("ref", ref), log.Err(err))
return name.Reference{}, false
}
return tag, true
})
}
// parseRepoDigests parses repo digests into name.Digest
func (a Artifact) parseRepoDigests(repoDigests []string) []name.Digest {
return lo.FilterMap(repoDigests, func(digestStr string, _ int) (name.Digest, bool) {
digest, err := name.NewDigest(digestStr)
if err != nil {
a.logger.Debug("Failed to parse repo digest", log.String("digest", digestStr), log.Err(err))
return name.Digest{}, false
}
return digest, true
})
}
// findMatchingRepoReference finds a RepoTag or RepoDigest that matches the artifact name
func (a Artifact) findMatchingRepoReference(artifactName string, repoTags []name.Tag, repoDigests []name.Digest) name.Reference {
func (a Artifact) findMatchingRepoReference(artifactName string, references []name.Reference) name.Reference {
// If there are no RepoTags or RepoDigests, return nil
if len(repoTags) == 0 && len(repoDigests) == 0 {
return nil
if len(references) == 0 {
return name.Reference{}
}
// Select the first available reference as fallback
fallback := cmp.Or[name.Reference](lo.FirstOrEmpty(repoTags), lo.FirstOrEmpty(repoDigests))
// Use the first available reference as fallback (tags take precedence over digests)
fallback := lo.FirstOrEmpty(references)
// TODO(knqyf263): refactor to use a more robust method instead of suffix-based detection
// Check if artifact name looks like a file path (tar archive)
@@ -240,22 +224,11 @@ func (a Artifact) findMatchingRepoReference(artifactName string, repoTags []name
}
artifactRefName := artifactRef.Name()
switch artifactRef.(type) {
case name.Digest:
// Try to find a matching digest from RepoDigests
if digest, ok := lo.Find(repoDigests, func(d name.Digest) bool {
return artifactRefName == d.Name()
}); ok {
return digest
}
case name.Tag:
// Try to find a matching tag from RepoTags
if tag, ok := lo.Find(repoTags, func(t name.Tag) bool {
return artifactRefName == t.Name()
}); ok {
return tag
}
// Try to find a matching digest from RepoTags/RepoDigests
if ref, ok := lo.Find(references, func(d name.Reference) bool {
return artifactRefName == d.Name()
}); ok {
return ref
}
// If no matching tag/digest found, use the first RepoTag or RepoDigest as fallback

View File

@@ -94,6 +94,7 @@ func (a Artifact) Inspect(ctx context.Context) (artifact.Reference, error) {
DiffIDs: bom.Metadata.DiffIDs,
RepoTags: bom.Metadata.RepoTags,
RepoDigests: bom.Metadata.RepoDigests,
Reference: bom.Metadata.Reference,
},
// Keep an original report

View File

@@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/internal/cachetest"
"github.com/aquasecurity/trivy/internal/testutil"
"github.com/aquasecurity/trivy/pkg/cache"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/fanal/artifact/sbom"
@@ -203,6 +204,7 @@ func TestArtifact_Inspect(t *testing.T) {
RepoTags: []string{
"maven-test-project:latest",
},
Reference: testutil.MustParseReference(t, "maven-test-project:latest"),
},
},
},

View File

@@ -39,6 +39,10 @@
{
"name": "aquasecurity:trivy:RepoTag",
"value": "maven-test-project:latest"
},
{
"name": "aquasecurity:trivy:Reference",
"value": "maven-test-project:latest"
}
]
}

View File

@@ -1,4 +1,4 @@
package image
package name
import (
"encoding/json"
@@ -13,11 +13,6 @@ type Reference struct {
name.Reference
}
// NewReference creates a new Reference from name.Reference
func NewReference(ref name.Reference) Reference {
return Reference{Reference: ref}
}
// ParseReference parses a string into a Reference
func ParseReference(s string) (Reference, error) {
if s == "" {
@@ -56,7 +51,7 @@ func (r *Reference) UnmarshalJSON(data []byte) error {
return nil
}
// IsEmpty returns true if the reference is empty
func (r Reference) IsEmpty() bool {
// IsZero returns true if the reference is empty (for omitzero support)
func (r Reference) IsZero() bool {
return lo.IsNil(r.Reference)
}

View File

@@ -1,4 +1,4 @@
package image_test
package name_test
import (
"encoding/json"
@@ -8,13 +8,13 @@ import (
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/internal/testutil"
"github.com/aquasecurity/trivy/pkg/fanal/image"
"github.com/aquasecurity/trivy/pkg/fanal/image/name"
)
func TestReference_MarshalJSON(t *testing.T) {
tests := []struct {
name string
ref image.Reference
ref name.Reference
want string
}{
{
@@ -29,7 +29,7 @@ func TestReference_MarshalJSON(t *testing.T) {
},
{
name: "empty reference",
ref: image.Reference{},
ref: name.Reference{},
want: `""`,
},
}
@@ -81,14 +81,14 @@ func TestReference_UnmarshalJSON(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var r image.Reference
var r name.Reference
err := json.Unmarshal([]byte(tt.json), &r)
tt.wantErr(t, err)
if err != nil {
return
}
assert.Equal(t, tt.wantIsEmpty, r.IsEmpty())
if !r.IsEmpty() {
assert.Equal(t, tt.wantIsEmpty, r.IsZero())
if !r.IsZero() {
assert.Equal(t, tt.want, r.String())
}
})
@@ -98,7 +98,7 @@ func TestReference_UnmarshalJSON(t *testing.T) {
func TestReference_String(t *testing.T) {
tests := []struct {
name string
ref image.Reference
ref name.Reference
want string
}{
{
@@ -128,7 +128,7 @@ func TestReference_String(t *testing.T) {
func TestReference_Context(t *testing.T) {
tests := []struct {
name string
ref image.Reference
ref name.Reference
want string
}{
{
@@ -158,7 +158,7 @@ func TestReference_Context(t *testing.T) {
func TestReference_IsEmpty(t *testing.T) {
tests := []struct {
name string
ref image.Reference
ref name.Reference
want bool
}{
{
@@ -168,14 +168,14 @@ func TestReference_IsEmpty(t *testing.T) {
},
{
name: "empty reference",
ref: image.Reference{},
ref: name.Reference{},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, tt.ref.IsEmpty())
assert.Equal(t, tt.want, tt.ref.IsZero())
})
}
}
@@ -188,7 +188,7 @@ func TestReference_JSONRoundTrip(t *testing.T) {
require.NoError(t, err)
// Unmarshal from JSON
var decoded image.Reference
var decoded name.Reference
err = json.Unmarshal(data, &decoded)
require.NoError(t, err)

View File

@@ -33,6 +33,7 @@ const (
PropertyRepoDigest = "RepoDigest"
PropertyDiffID = "DiffID"
PropertyRepoTag = "RepoTag"
PropertyReference = "Reference"
PropertyLabelsPrefix = "Labels"
// Package properties

View File

@@ -15,6 +15,7 @@ import (
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/dependency"
"github.com/aquasecurity/trivy/pkg/fanal/image/name"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/purl"
@@ -105,6 +106,10 @@ func (m *Decoder) decodeRoot(s *types.SBOM) error {
s.Metadata.DiffIDs = append(s.Metadata.DiffIDs, prop.Value)
case core.PropertyRepoTag:
s.Metadata.RepoTags = append(s.Metadata.RepoTags, prop.Value)
case core.PropertyReference:
if s.Metadata.Reference, err = name.ParseReference(prop.Value); err != nil {
m.logger.Warn("Failed to parse image reference", log.String("value", prop.Value), log.Err(err))
}
}
}
return nil

View File

@@ -167,6 +167,13 @@ func (e *Encoder) rootComponent(r types.Report) (*core.Component, error) {
})
}
if !r.Metadata.Reference.IsZero() {
props = append(props, core.Property{
Name: core.PropertyReference,
Value: r.Metadata.Reference.String(),
})
}
root.Properties = filterProperties(props)
return root, nil

View File

@@ -92,6 +92,7 @@ func (s Service) ScanArtifact(ctx context.Context, options types.ScanOptions) (t
DiffIDs: artifactInfo.ImageMetadata.DiffIDs,
RepoTags: artifactInfo.ImageMetadata.RepoTags,
RepoDigests: artifactInfo.ImageMetadata.RepoDigests,
Reference: artifactInfo.ImageMetadata.Reference,
ImageConfig: artifactInfo.ImageMetadata.ConfigFile,
Size: scanResponse.Layers.TotalSize(),
Layers: lo.Ternary(len(scanResponse.Layers) > 0, scanResponse.Layers, nil),
@@ -125,7 +126,7 @@ func (s Service) generateArtifactID(artifactInfo artifact.Reference) string {
// Use the Reference field if available
ref := artifactInfo.ImageMetadata.Reference
if ref.IsEmpty() {
if ref.IsZero() {
// Reference is empty when RepoTags and RepoDigests are both empty.
// This happens in the following cases:
// 1. Images built without tags (e.g., "docker build ." without -t flag)

View File

@@ -12,6 +12,7 @@ import (
"github.com/aquasecurity/trivy-db/pkg/db"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/internal/dbtest"
"github.com/aquasecurity/trivy/internal/testutil"
"github.com/aquasecurity/trivy/pkg/cache"
"github.com/aquasecurity/trivy/pkg/clock"
"github.com/aquasecurity/trivy/pkg/fanal/applier"
@@ -77,6 +78,7 @@ func TestScanner_ScanArtifact(t *testing.T) {
DiffID: "sha256:beee9f30bc1f711043e78d4a2be0668955d4b761d587d6f60c2c8dc081efb203",
},
},
Reference: testutil.MustParseReference(t, "alpine:3.11"),
ImageConfig: v1.ConfigFile{
Architecture: "amd64",
Container: "fb71ddde5f6411a82eb056a9190f0cc1c80d7f77a8509ee90a2054428edb0024",

View File

@@ -5,6 +5,7 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1" // nolint: goimports
"github.com/aquasecurity/trivy/pkg/fanal/image/name"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/sbom/core"
)
@@ -37,12 +38,13 @@ type Metadata struct {
OS *ftypes.OS `json:",omitempty"`
// Container image
ImageID string `json:",omitempty"`
DiffIDs []string `json:",omitempty"`
RepoTags []string `json:",omitempty"`
RepoDigests []string `json:",omitempty"`
ImageConfig v1.ConfigFile `json:",omitzero"`
Layers ftypes.Layers `json:",omitzero"`
ImageID string `json:",omitempty"`
DiffIDs []string `json:",omitempty"`
RepoTags []string `json:",omitempty"`
RepoDigests []string `json:",omitempty"`
Reference name.Reference `json:",omitzero"`
ImageConfig v1.ConfigFile `json:",omitzero"`
Layers ftypes.Layers `json:",omitzero"`
// Git repository
RepoURL string `json:",omitzero"`