Skip to content

Commit 60a3b4b

Browse files
authored
Feature/docker validate sha (#1386)
* Add --validate-sha flag for Docker push command
1 parent 99696c0 commit 60a3b4b

File tree

3 files changed

+56
-12
lines changed

3 files changed

+56
-12
lines changed

artifactory/utils/container/buildinfo.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ package container
22

33
import (
44
"encoding/json"
5-
ioutils "github.com/jfrog/gofrog/io"
65
"os"
76
"path"
87
"strings"
98

9+
ioutils "github.com/jfrog/gofrog/io"
10+
1011
buildinfo "github.com/jfrog/build-info-go/entities"
1112

1213
artutils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
@@ -91,10 +92,23 @@ func (builder *buildInfoBuilder) getSearchableRepo() string {
9192

9293
// Set build properties on image layers in Artifactory.
9394
func setBuildProperties(buildName, buildNumber, project string, imageLayers []utils.ResultItem, serviceManager artifactory.ArtifactoryServicesManager) (err error) {
95+
// Skip if no build info is provided
96+
if buildName == "" || buildNumber == "" {
97+
log.Debug("Skipping setting properties - build name and build number are required")
98+
return nil
99+
}
100+
94101
props, err := build.CreateBuildProperties(buildName, buildNumber, project)
95102
if err != nil {
96103
return
97104
}
105+
106+
// Skip if no properties were created
107+
if len(props) == 0 {
108+
log.Debug("Skipping setting properties - no properties created")
109+
return nil
110+
}
111+
98112
pathToFile, err := writeLayersToFile(imageLayers)
99113
if err != nil {
100114
return

artifactory/utils/container/remoteagent.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,14 @@ func (rabib *RemoteAgentBuildInfoBuilder) Build(module string) (*buildinfo.Build
5353
// Search for image manifest and layers in Artifactory.
5454
func (rabib *RemoteAgentBuildInfoBuilder) handleManifest(resultMap map[string]*utils.ResultItem) (map[string]*utils.ResultItem, *manifest, error) {
5555
if manifest, ok := resultMap["manifest.json"]; ok {
56-
err := rabib.isVerifiedManifest(manifest)
57-
if err != nil {
58-
return nil, nil, err
59-
56+
if !rabib.isVerifiedManifest(manifest) {
57+
log.Debug("Manifest verification failed, continuing with SHA-based validation...")
6058
}
6159
manifest, err := getManifest(resultMap, rabib.buildInfoBuilder.serviceManager, rabib.buildInfoBuilder.repositoryDetails.key)
6260
if err != nil {
6361
return nil, nil, err
6462
}
65-
// // Manifest may hold 'empty layers'. As a result, promotion will fail to promote the same layer more than once.
63+
// Manifest may hold 'empty layers'. As a result, promotion will fail to promote the same layer more than once.
6664
rabib.buildInfoBuilder.imageSha2 = manifest.Config.Digest
6765
log.Debug("Found manifest.json. Proceeding to create build-info.")
6866
return resultMap, manifest, nil
@@ -95,6 +93,8 @@ func (rabib *RemoteAgentBuildInfoBuilder) searchImage() (resultMap map[string]*u
9593
// Search image's manifest.
9694
manifestPathsCandidates := getManifestPaths(imagePath, rabib.buildInfoBuilder.getSearchableRepo(), Push)
9795
log.Debug("Start searching for image manifest.json")
96+
97+
// First try standard tag-based search
9898
for _, path := range manifestPathsCandidates {
9999
log.Debug(`Searching in:"` + path + `"`)
100100
resultMap, err = performSearch(path, rabib.buildInfoBuilder.serviceManager)
@@ -108,15 +108,39 @@ func (rabib *RemoteAgentBuildInfoBuilder) searchImage() (resultMap map[string]*u
108108
return resultMap, nil
109109
}
110110
}
111+
112+
// If tag-based search failed and we have a SHA, try SHA-based search
113+
if rabib.manifestSha2 != "" {
114+
log.Debug("Tag-based search failed. Trying SHA-based search with: " + rabib.manifestSha2)
115+
// Extract repository path without tag
116+
repoPath := imagePath[:strings.LastIndex(imagePath, "/")]
117+
// Convert SHA format from sha256:xxx to sha256__xxx for Artifactory path format
118+
shaPath := strings.Replace(rabib.manifestSha2, ":", "__", 1)
119+
// Search for the image using SHA path
120+
shaSearchPath := repoPath + "/" + shaPath + "/*"
121+
log.Debug(`Searching by SHA in:"` + shaSearchPath + `"`)
122+
resultMap, err = performSearch(shaSearchPath, rabib.buildInfoBuilder.serviceManager)
123+
if err != nil {
124+
return nil, err
125+
}
126+
if resultMap != nil && (resultMap["list.manifest.json"] != nil || resultMap["manifest.json"] != nil) {
127+
log.Info("Found image by SHA digest in repository")
128+
return resultMap, nil
129+
}
130+
}
131+
111132
return nil, errorutils.CheckErrorf(imageNotFoundErrorMessage, rabib.buildInfoBuilder.image.name)
112133
}
113134

114-
// Verify manifest's sha256. If there is no match, return nil.
115-
func (rabib *RemoteAgentBuildInfoBuilder) isVerifiedManifest(imageManifest *utils.ResultItem) error {
135+
// Verify manifest's sha256. Returns true if manifest is verified, false otherwise.
136+
func (rabib *RemoteAgentBuildInfoBuilder) isVerifiedManifest(imageManifest *utils.ResultItem) bool {
116137
if imageManifest.GetProperty("docker.manifest.digest") != rabib.manifestSha2 {
117-
return errorutils.CheckErrorf(`Found incorrect manifest.json file. Expects digest "` + rabib.manifestSha2 + `" found "` + imageManifest.GetProperty("docker.manifest.digest"))
138+
manifestDigest := imageManifest.GetProperty("docker.manifest.digest")
139+
log.Warn("Manifest digest mismatch detected. Local image digest: " + rabib.manifestSha2 + ", Repository digest: " + manifestDigest)
140+
log.Info("Proceeding with SHA-based validation to ensure correct image identification...")
141+
return false
118142
}
119-
return nil
143+
return true
120144
}
121145

122146
func getFatManifestRoot(fatManifestPath string) string {

utils/coreutils/cmdutils.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package coreutils
22

33
import (
4-
"github.com/forPelevin/gomoji"
5-
"github.com/jfrog/jfrog-client-go/utils/log"
64
"strconv"
75
"strings"
86

7+
"github.com/forPelevin/gomoji"
8+
"github.com/jfrog/jfrog-client-go/utils/log"
9+
910
"github.com/gookit/color"
1011
"github.com/jfrog/jfrog-client-go/utils/errorutils"
1112
)
@@ -169,6 +170,11 @@ func ExtractSkipLoginFromArgs(args []string) (cleanArgs []string, skipLogin bool
169170
return extractBoolOptionFromArgs(args, "skip-login")
170171
}
171172

173+
// Used by docker
174+
func ExtractBoolFlagFromArgs(args []string, flagName string) (cleanArgs []string, flagValue bool, err error) {
175+
return extractBoolOptionFromArgs(args, flagName)
176+
}
177+
172178
// Used by docker
173179
func ExtractFailFromArgs(args []string) (cleanArgs []string, fail bool, err error) {
174180
return extractBoolOptionFromArgs(args, "fail")

0 commit comments

Comments
 (0)