From dbe9790147b8ec4ad6aabe7a6665edfe998d99d5 Mon Sep 17 00:00:00 2001 From: Wang Yan Date: Tue, 12 Mar 2024 12:27:34 +0800 Subject: [PATCH] add generate sbom object utility (#20097) * add generate sbom object utility Leverage the go-containerregistry to generate the oci object for sbom and add it as an accessory of the subject artifact. Signed-off-by: wang yan * remove vendor Signed-off-by: wang yan * resolve comments Signed-off-by: wang yan * fix ut Signed-off-by: wang yan * resolve comments Signed-off-by: wang yan * remove the todo comments Signed-off-by: wang yan --------- Signed-off-by: wang yan --- src/controller/scan/base_controller.go | 1 + src/go.mod | 14 ++- src/go.sum | 22 +++++ src/pkg/scan/rest/v1/models.go | 2 + src/pkg/scan/util.go | 95 +++++++++++++++++++ src/pkg/scan/util_test.go | 64 +++++++++++++ src/server/middleware/subject/subject_test.go | 12 +-- src/server/registry/referrers_test.go | 6 +- 8 files changed, 204 insertions(+), 12 deletions(-) create mode 100644 src/pkg/scan/util.go create mode 100644 src/pkg/scan/util_test.go diff --git a/src/controller/scan/base_controller.go b/src/controller/scan/base_controller.go index d5e36737f..143687516 100644 --- a/src/controller/scan/base_controller.go +++ b/src/controller/scan/base_controller.go @@ -994,6 +994,7 @@ func (bc *basicController) launchScanJob(ctx context.Context, param *launchScanJ Digest: param.Artifact.Digest, Tag: param.Tag, MimeType: param.Artifact.ManifestMediaType, + Size: param.Artifact.Size, }, } diff --git a/src/go.mod b/src/go.mod index 12855b83c..72cce223f 100644 --- a/src/go.mod +++ b/src/go.mod @@ -21,18 +21,19 @@ require ( github.com/go-asn1-ber/asn1-ber v1.5.5 github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-openapi/errors v0.21.0 - github.com/go-openapi/loads v0.21.2 // indirect + github.com/go-openapi/loads v0.21.2 github.com/go-openapi/runtime v0.26.2 - github.com/go-openapi/spec v0.20.11 // indirect + github.com/go-openapi/spec v0.20.11 github.com/go-openapi/strfmt v0.22.0 github.com/go-openapi/swag v0.22.7 - github.com/go-openapi/validate v0.22.3 // indirect + github.com/go-openapi/validate v0.22.3 github.com/go-redis/redis/v8 v8.11.4 github.com/gocarina/gocsv v0.0.0-20210516172204-ca9e8a8ddea8 github.com/gocraft/work v0.5.1 github.com/golang-jwt/jwt/v5 v5.2.0 github.com/golang-migrate/migrate/v4 v4.16.2 github.com/gomodule/redigo v2.0.0+incompatible + github.com/google/go-containerregistry v0.19.0 github.com/google/uuid v1.6.0 github.com/gorilla/csrf v1.6.2 github.com/gorilla/handlers v1.5.2 @@ -95,10 +96,14 @@ require ( github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/denverdino/aliyungo v0.0.0-20191227032621-df38c6fa730c // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dnaeon/go-vcr v1.2.0 // indirect + github.com/docker/cli v24.0.6+incompatible // indirect + github.com/docker/docker v24.0.7+incompatible // indirect + github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect @@ -130,10 +135,12 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.16.5 // indirect github.com/magiconair/properties v1.8.5 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -154,6 +161,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect + github.com/vbatts/tar-split v0.11.3 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/volcengine/volc-sdk-golang v1.0.23 // indirect go.mongodb.org/mongo-driver v1.13.1 // indirect diff --git a/src/go.sum b/src/go.sum index f6aeb03d7..2ca9fa57f 100644 --- a/src/go.sum +++ b/src/go.sum @@ -46,6 +46,7 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/FZambia/sentinel v1.1.0 h1:qrCBfxc8SvJihYNjBWgwUI93ZCvFe/PJIPTHKmlp8a8= github.com/FZambia/sentinel v1.1.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI= @@ -109,12 +110,15 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo= github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -133,8 +137,12 @@ github.com/distribution/distribution v2.8.2+incompatible h1:k9+4DKdOG+quPFZXT/mU github.com/distribution/distribution v2.8.2+incompatible/go.mod h1:EgLm2NgWtdKgzF9NpMzUKgzmR7AMmb0VQi2B+ZzDRjc= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= +github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= @@ -274,6 +282,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.19.0 h1:uIsMRBV7m/HDkDxE/nXMnv1q+lOOSPlQ/ywc5JbB8Ic= +github.com/google/go-containerregistry v0.19.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -406,6 +416,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -450,6 +462,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= @@ -545,6 +559,7 @@ github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUz github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -558,6 +573,7 @@ github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -598,8 +614,11 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/tencentcloud/tencentcloud-sdk-go v1.0.62 h1:Vnr3IqaafEuQUciG6D6EaeLJm26Mg8sjAfbI4OoeauM= github.com/tencentcloud/tencentcloud-sdk-go v1.0.62/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= +github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -799,6 +818,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -945,6 +965,8 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= helm.sh/helm/v3 v3.14.2 h1:V71fv+NGZv0icBlr+in1MJXuUIHCiPG1hW9gEBISTIA= helm.sh/helm/v3 v3.14.2/go.mod h1:2itvvDv2WSZXTllknfQo6j7u3VVgMAvm8POCDgYH424= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/src/pkg/scan/rest/v1/models.go b/src/pkg/scan/rest/v1/models.go index c7579cd74..50de0cbf5 100644 --- a/src/pkg/scan/rest/v1/models.go +++ b/src/pkg/scan/rest/v1/models.go @@ -150,6 +150,8 @@ type Artifact struct { Digest string `json:"digest"` // The mime type of the scanned artifact MimeType string `json:"mime_type"` + // The size the scanned artifact + Size int64 `json:"size"` } // Registry represents Registry connection settings. diff --git a/src/pkg/scan/util.go b/src/pkg/scan/util.go new file mode 100644 index 000000000..e7b65b1e0 --- /dev/null +++ b/src/pkg/scan/util.go @@ -0,0 +1,95 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package scan + +import ( + "crypto/tls" + "fmt" + "net/http" + + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/empty" + "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/static" + "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + + "github.com/goharbor/harbor/src/controller/robot" + v1sq "github.com/goharbor/harbor/src/pkg/scan/rest/v1" +) + +type Insecure bool + +func (i Insecure) RemoteOptions() []remote.Option { + tr := http.DefaultTransport.(*http.Transport).Clone() + tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: bool(i)} + return []remote.Option{remote.WithTransport(tr)} +} + +type referrer struct { + Insecure +} + +// GenAccessoryArt composes the accessory oci object and push it back to harbor core as an accessory of the scanned artifact. +func GenAccessoryArt(sq v1sq.ScanRequest, accData []byte, accAnnotations map[string]string, mediaType string, robot robot.Robot) (string, error) { + accArt, err := mutate.Append(empty.Image, mutate.Addendum{ + Layer: static.NewLayer(accData, ocispec.MediaTypeImageLayer), + History: v1.History{ + Author: "harbor", + CreatedBy: "harbor", + Created: v1.Time{}, // static + }, + }) + if err != nil { + return "", err + } + + dg, err := digest.Parse(sq.Artifact.Digest) + if err != nil { + return "", err + } + accSubArt := &v1.Descriptor{ + MediaType: types.MediaType(sq.Artifact.MimeType), + Size: sq.Artifact.Size, + Digest: v1.Hash{ + Algorithm: dg.Algorithm().String(), + Hex: dg.Hex(), + }, + } + // TODO to leverage the artifactType of distribution spec v1.1 to specify the sbom type. + // https://github.com/google/go-containerregistry/issues/1832 + accArt = mutate.MediaType(accArt, ocispec.MediaTypeImageManifest) + accArt = mutate.ConfigMediaType(accArt, types.MediaType(mediaType)) + accArt = mutate.Subject(accArt, *accSubArt).(v1.Image) + accArt = mutate.Annotations(accArt, accAnnotations).(v1.Image) + + digest, err := accArt.Digest() + if err != nil { + return "", err + } + accRef, err := name.ParseReference(fmt.Sprintf("%s/%s@%s", sq.Registry.URL, sq.Artifact.Repository, digest.String())) + if err != nil { + return "", err + } + opts := append(referrer{Insecure: true}.RemoteOptions(), remote.WithAuth(&authn.Basic{Username: robot.Name, Password: robot.Secret})) + if err := remote.Write(accRef, accArt, opts...); err != nil { + return "", err + } + return digest.String(), nil +} diff --git a/src/pkg/scan/util_test.go b/src/pkg/scan/util_test.go new file mode 100644 index 000000000..f293f026a --- /dev/null +++ b/src/pkg/scan/util_test.go @@ -0,0 +1,64 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package scan + +import ( + "net/http/httptest" + "net/url" + "testing" + + "github.com/google/go-containerregistry/pkg/registry" + "github.com/stretchr/testify/assert" + + "github.com/goharbor/harbor/src/controller/robot" + rm "github.com/goharbor/harbor/src/pkg/robot/model" + v1sq "github.com/goharbor/harbor/src/pkg/scan/rest/v1" +) + +func TestGenAccessoryArt(t *testing.T) { + server := httptest.NewServer(registry.New(registry.WithReferrersSupport(true))) + defer server.Close() + u, err := url.Parse(server.URL) + if err != nil { + t.Fatal(err) + } + + sq := v1sq.ScanRequest{ + Registry: &v1sq.Registry{ + URL: u.Host, + }, + Artifact: &v1sq.Artifact{ + Repository: "library/hello-world", + Tag: "latest", + Size: 1234, + MimeType: "application/vnd.docker.distribution.manifest.v2+json", + Digest: "sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7", + }, + } + r := robot.Robot{ + Robot: rm.Robot{ + Name: "admin", + Secret: "Harbor12345", + }, + } + + annotations := map[string]string{ + "created-by": "trivy", + "org.opencontainers.artifact.description": "SPDX JSON SBOM", + } + s, err := GenAccessoryArt(sq, []byte(`{"name": "harborAccTest", "version": "1.0"}`), annotations, "application/vnd.goharbor.harbor.main.v1", r) + assert.Nil(t, err) + assert.Equal(t, "sha256:8de6104b79deca0253ff8667692f03e34753494c77ec81f631b45aad69223c18", s) +} diff --git a/src/server/middleware/subject/subject_test.go b/src/server/middleware/subject/subject_test.go index 5dc11c333..323b0c78b 100644 --- a/src/server/middleware/subject/subject_test.go +++ b/src/server/middleware/subject/subject_test.go @@ -44,19 +44,19 @@ func (suite *MiddlewareTestSuite) prepare(name, digset string, withoutSub ...boo "schemaVersion":2, "mediaType":"application/vnd.oci.image.manifest.v1+json", "config":{ - "mediaType":"application/vnd.example.sbom", + "mediaType":"application/vnd.example.main", "size":2, "digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a" }, "layers":[ { - "mediaType":"application/vnd.example.sbom.text", + "mediaType":"application/vnd.example.main.text", "size":37, "digest":"sha256:45592a729ef6884ea3297e9510d79104f27aeef5f4919b3a921e3abb7f469709" } ], "annotations":{ - "org.example.sbom.format":"text" + "org.example.main.format":"text" }, "subject":{ "mediaType":"application/vnd.oci.image.manifest.v1+json", @@ -70,19 +70,19 @@ func (suite *MiddlewareTestSuite) prepare(name, digset string, withoutSub ...boo "schemaVersion":2, "mediaType":"application/vnd.oci.image.manifest.v1+json", "config":{ - "mediaType":"application/vnd.example.sbom", + "mediaType":"application/vnd.example.main", "size":2, "digest":"%s" }, "layers":[ { - "mediaType":"application/vnd.example.sbom.text", + "mediaType":"application/vnd.example.main.text", "size":37, "digest":"sha256:45592a729ef6884ea3297e9510d79104f27aeef5f4919b3a921e3abb7f469709" } ], "annotations":{ - "org.example.sbom.format":"text" + "org.example.main.format":"text" }}`, digset) } diff --git a/src/server/registry/referrers_test.go b/src/server/registry/referrers_test.go index 473fb0c57..27f1deec3 100644 --- a/src/server/registry/referrers_test.go +++ b/src/server/registry/referrers_test.go @@ -37,7 +37,7 @@ func TestReferrersHandlerOK(t *testing.T) { Return(&artifact.Artifact{ Digest: digestVal, ManifestMediaType: "application/vnd.oci.image.manifest.v1+json", - MediaType: "application/vnd.example.sbom", + MediaType: "application/vnd.example.main", Size: 1000, Annotations: map[string]string{ "name": "test-image", @@ -72,8 +72,8 @@ func TestReferrersHandlerOK(t *testing.T) { } index := &ocispec.Index{} json.Unmarshal([]byte(rec.Body.String()), index) - if index.Manifests[0].ArtifactType != "application/vnd.example.sbom" { - t.Errorf("Expected response body %s, but got %s", "application/vnd.example.sbom", rec.Body.String()) + if index.Manifests[0].ArtifactType != "application/vnd.example.main" { + t.Errorf("Expected response body %s, but got %s", "application/vnd.example.main", rec.Body.String()) } }