@@ -37,6 +37,7 @@ import (
3737 "github.com/jfrog/jfrog-cli-security/commands/audit"
3838 "github.com/jfrog/jfrog-cli-security/sca/bom/buildinfo"
3939 "github.com/jfrog/jfrog-cli-security/sca/bom/buildinfo/technologies"
40+ "github.com/jfrog/jfrog-cli-security/sca/bom/buildinfo/technologies/docker"
4041 "github.com/jfrog/jfrog-cli-security/sca/bom/buildinfo/technologies/python"
4142 "github.com/jfrog/jfrog-cli-security/utils"
4243 "github.com/jfrog/jfrog-cli-security/utils/formats"
@@ -102,6 +103,7 @@ var supportedTech = map[techutils.Technology]func(ca *CurationAuditCommand) (boo
102103 techutils .Gem : func (ca * CurationAuditCommand ) (bool , error ) {
103104 return ca .checkSupportByVersionOrEnv (techutils .Gem , MinArtiGradleGemSupport )
104105 },
106+ techutils .Docker : func (ca * CurationAuditCommand ) (bool , error ) { return true , nil },
105107}
106108
107109func (ca * CurationAuditCommand ) checkSupportByVersionOrEnv (tech techutils.Technology , minArtiVersion string ) (bool , error ) {
@@ -217,6 +219,7 @@ type CurationAuditCommand struct {
217219 workingDirs []string
218220 OriginPath string
219221 parallelRequests int
222+ dockerImageName string
220223 audit.AuditParamsInterface
221224}
222225
@@ -253,6 +256,15 @@ func (ca *CurationAuditCommand) SetParallelRequests(threads int) *CurationAuditC
253256 return ca
254257}
255258
259+ func (ca * CurationAuditCommand ) DockerImageName () string {
260+ return ca .dockerImageName
261+ }
262+
263+ func (ca * CurationAuditCommand ) SetDockerImageName (dockerImageName string ) * CurationAuditCommand {
264+ ca .dockerImageName = dockerImageName
265+ return ca
266+ }
267+
256268func (ca * CurationAuditCommand ) Run () (err error ) {
257269 rootDir , err := os .Getwd ()
258270 if err != nil {
@@ -350,6 +362,10 @@ func getPolicyAndConditionId(policy, condition string) string {
350362
351363func (ca * CurationAuditCommand ) doCurateAudit (results map [string ]* CurationReport ) error {
352364 techs := techutils .DetectedTechnologiesList ()
365+ if ca .DockerImageName () != "" {
366+ log .Debug (fmt .Sprintf ("Docker image name '%s' was provided, running Docker curation audit." , ca .DockerImageName ()))
367+ techs = []string {techutils .Docker .String ()}
368+ }
353369 for _ , tech := range techs {
354370 supportedFunc , ok := supportedTech [techutils .Technology (tech )]
355371 if ! ok {
@@ -426,6 +442,8 @@ func (ca *CurationAuditCommand) getBuildInfoParamsByTech() (technologies.BuildIn
426442 NpmOverwritePackageLock : true ,
427443 // Python params
428444 PipRequirementsFile : ca .PipRequirementsFile (),
445+ // Docker params
446+ DockerImageName : ca .DockerImageName (),
429447 // NuGet params
430448 SolutionFilePath : ca .SolutionFilePath (),
431449 }, err
@@ -718,6 +736,16 @@ func (ca *CurationAuditCommand) CommandName() string {
718736}
719737
720738func (ca * CurationAuditCommand ) SetRepo (tech techutils.Technology ) error {
739+ // If the technology is Docker, we need to get the repository config from the Docker image name
740+ if tech == techutils .Docker {
741+ repoConfig , err := docker .GetDockerRepositoryConfig (ca .DockerImageName ())
742+ if err != nil {
743+ return err
744+ }
745+ ca .setPackageManagerConfig (repoConfig )
746+ return nil
747+ }
748+
721749 resolverParams , err := ca .getRepoParams (techutils .TechToProjectType [tech ])
722750 if err != nil {
723751 return err
@@ -950,6 +978,9 @@ func getUrlNameAndVersionByTech(tech techutils.Technology, node *xrayUtils.Graph
950978 case techutils .Nuget :
951979 downloadUrls , name , version = getNugetNameScopeAndVersion (node .Id , artiUrl , repo )
952980 return
981+ case techutils .Docker :
982+ downloadUrls , name , version = getDockerNameAndVersion (node .Id , artiUrl , repo )
983+ return
953984 }
954985 return
955986}
@@ -1134,6 +1165,39 @@ func buildNpmDownloadUrl(url, repo, name, scope, version string) []string {
11341165 return []string {packageUrl }
11351166}
11361167
1168+ func getDockerNameAndVersion (id , artiUrl , repo string ) (downloadUrls []string , name , version string ) {
1169+ if id == "" {
1170+ return
1171+ }
1172+
1173+ id = strings .TrimPrefix (id , "docker://" )
1174+
1175+ sha256Idx := strings .Index (id , ":sha256:" )
1176+ tagIdx := strings .LastIndex (id , ":" )
1177+
1178+ switch {
1179+ // Example: docker://nginx:sha256:abc123def456
1180+ case sha256Idx > 0 :
1181+ name = id [:sha256Idx ]
1182+ version = id [sha256Idx + 1 :]
1183+ // Example: docker://nginx:1.21
1184+ case tagIdx > 0 :
1185+ name = id [:tagIdx ]
1186+ version = id [tagIdx + 1 :]
1187+ // Example: docker://nginx (no tag specified, defaults to "latest")
1188+ default :
1189+ name = id
1190+ version = "latest"
1191+ }
1192+
1193+ if artiUrl != "" && repo != "" {
1194+ downloadUrls = []string {fmt .Sprintf ("%s/api/docker/%s/v2/%s/manifests/%s" ,
1195+ strings .TrimSuffix (artiUrl , "/" ), repo , name , version )}
1196+ }
1197+
1198+ return
1199+ }
1200+
11371201func GetCurationOutputFormat (formatFlagVal string ) (format outFormat.OutputFormat , err error ) {
11381202 // Default print format is table.
11391203 format = outFormat .Table
0 commit comments