diff --git a/Makefile b/Makefile index 95eb9b3..4671828 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,9 @@ GOARCH = $(shell go env GOARCH) # ---------------------------------------------------------------------------------------------------------------------- export PROJECT_DIR = $(CURDIR) +prereq: + $(GOCMD) install go.uber.org/mock/mockgen@v0.4.0 + clean-mock: @find . -name "*_mock.go" -delete diff --git a/evidence/cli/command.go b/evidence/cli/command.go index 3e1b7fd..68800a3 100644 --- a/evidence/cli/command.go +++ b/evidence/cli/command.go @@ -3,9 +3,10 @@ package cli //go:generate ${PROJECT_DIR}/scripts/mockgen.sh ${GOFILE} import ( + "github.com/jfrog/jfrog-cli-core/v2/plugins/components" coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config" ) type EvidenceCommands interface { - CreateEvidence(*coreConfig.ServerDetails) error + CreateEvidence(ctx *components.Context, serverDetails *coreConfig.ServerDetails) error } diff --git a/evidence/cli/command_build.go b/evidence/cli/command_build.go index b7742f1..226968c 100644 --- a/evidence/cli/command_build.go +++ b/evidence/cli/command_build.go @@ -4,6 +4,7 @@ import ( "github.com/jfrog/jfrog-cli-artifactory/evidence" "github.com/jfrog/jfrog-cli-core/v2/plugins/components" coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-client-go/utils/errorutils" ) type evidenceBuildCommand struct { @@ -18,14 +19,27 @@ func NewEvidenceBuildCommand(ctx *components.Context, execute execCommandFunc) E } } -func (erc *evidenceBuildCommand) CreateEvidence(serverDetails *coreConfig.ServerDetails) error { +func (ebc *evidenceBuildCommand) CreateEvidence(ctx *components.Context, serverDetails *coreConfig.ServerDetails) error { + err := ebc.validateEvidenceBuildContext(ctx) + if err != nil { + return err + } + createCmd := evidence.NewCreateEvidenceBuild( serverDetails, - erc.ctx.GetStringFlagValue(predicate), - erc.ctx.GetStringFlagValue(predicateType), - erc.ctx.GetStringFlagValue(key), - erc.ctx.GetStringFlagValue(keyId), - erc.ctx.GetStringFlagValue(project), - erc.ctx.GetStringFlagValue(build)) - return erc.execute(createCmd) + ebc.ctx.GetStringFlagValue(predicate), + ebc.ctx.GetStringFlagValue(predicateType), + ebc.ctx.GetStringFlagValue(key), + ebc.ctx.GetStringFlagValue(keyId), + ebc.ctx.GetStringFlagValue(project), + ebc.ctx.GetStringFlagValue(buildName), + ebc.ctx.GetStringFlagValue(buildNumber)) + return ebc.execute(createCmd) +} + +func (ebc *evidenceBuildCommand) validateEvidenceBuildContext(ctx *components.Context) error { + if !ctx.IsFlagSet(buildNumber) || assertValueProvided(ctx, buildNumber) != nil { + return errorutils.CheckErrorf("'buildNumber' is a mandatory field for creating a Release Bundle evidence: --%s", buildNumber) + } + return nil } diff --git a/evidence/cli/command_controller.go b/evidence/cli/command_cli.go similarity index 86% rename from evidence/cli/command_controller.go rename to evidence/cli/command_cli.go index fee5a7b..d4a3472 100644 --- a/evidence/cli/command_controller.go +++ b/evidence/cli/command_cli.go @@ -26,12 +26,10 @@ func GetCommands() []components.Command { } } -var execFunc = func(command commands.Command) error { - return commands.Exec(command) -} +var execFunc = commands.Exec func createEvidence(c *components.Context) error { - if err := validateCreateEvidenceContext(c); err != nil { + if err := validateCreateEvidenceCommonContext(c); err != nil { return err } subject, err := getAndValidateSubject(c) @@ -45,20 +43,20 @@ func createEvidence(c *components.Context) error { var command EvidenceCommands switch subject { - case repoPath: + case subjectRepoPath: command = NewEvidenceCustomCommand(c, execFunc) case releaseBundle: command = NewEvidenceReleaseBundleCommand(c, execFunc) - case build: + case buildName: command = NewEvidenceBuildCommand(c, execFunc) default: return errors.New("unsupported subject") } - return command.CreateEvidence(serverDetails) + return command.CreateEvidence(c, serverDetails) } -func validateCreateEvidenceContext(c *components.Context) error { +func validateCreateEvidenceCommonContext(c *components.Context) error { if show, err := pluginsCommon.ShowCmdHelpIfNeeded(c, c.Arguments); show || err != nil { return err } @@ -68,13 +66,13 @@ func validateCreateEvidenceContext(c *components.Context) error { } if !c.IsFlagSet(predicate) || assertValueProvided(c, predicate) != nil { - return errorutils.CheckErrorf("'predicate' is a mandatory field for creating a custom evidence: --%s", predicate) + return errorutils.CheckErrorf("'predicate' is a mandatory field for creating evidence: --%s", predicate) } if !c.IsFlagSet(predicateType) || assertValueProvided(c, predicateType) != nil { - return errorutils.CheckErrorf("'predicate-type' is a mandatory field for creating a custom evidence: --%s", predicateType) + return errorutils.CheckErrorf("'predicate-type' is a mandatory field for creating evidence: --%s", predicateType) } if !c.IsFlagSet(key) || assertValueProvided(c, key) != nil { - return errorutils.CheckErrorf("'key' is a mandatory field for creating a custom evidence: --%s", key) + return errorutils.CheckErrorf("'key' is a mandatory field for creating evidence: --%s", key) } return nil } @@ -88,7 +86,7 @@ func getAndValidateSubject(c *components.Context) (string, error) { } if len(foundSubjects) == 0 { - return "", errorutils.CheckErrorf("Subject must be one of the fields: [%s]", strings.Join(subjectTypes, ", ")) + return "", errorutils.CheckErrorf("subject must be one of the fields: [%s]", strings.Join(subjectTypes, ", ")) } if len(foundSubjects) > 1 { return "", errorutils.CheckErrorf("multiple subjects found: [%s]", strings.Join(foundSubjects, ", ")) diff --git a/evidence/cli/command_cli_test.go b/evidence/cli/command_cli_test.go new file mode 100644 index 0000000..e12e93a --- /dev/null +++ b/evidence/cli/command_cli_test.go @@ -0,0 +1,125 @@ +package cli + +import ( + "flag" + "github.com/golang/mock/gomock" + "github.com/jfrog/jfrog-cli-core/v2/common/commands" + "github.com/jfrog/jfrog-cli-core/v2/plugins/components" + "github.com/stretchr/testify/assert" + "github.com/urfave/cli" + "testing" +) + +func TestCreateEvidence_Context(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + app := cli.NewApp() + app.Commands = []cli.Command{ + { + Name: "create", + }, + } + set := flag.NewFlagSet(predicate, 0) + ctx := cli.NewContext(app, set, nil) + + tests := []struct { + name string + flags []components.Flag + expectErr bool + }{ + { + name: "InvalidContext - Missing Subject", + flags: []components.Flag{ + setDefaultValue(predicate, predicate), + setDefaultValue(predicateType, predicateType), + setDefaultValue(key, key), + }, + expectErr: true, + }, + { + name: "InvalidContext - Missing Predicate", + flags: []components.Flag{ + setDefaultValue("", ""), + setDefaultValue(predicateType, "InToto"), + setDefaultValue(key, "PGP"), + }, + expectErr: true, + }, + { + name: "InvalidContext - Subject Duplication", + flags: []components.Flag{ + setDefaultValue(predicate, predicate), + setDefaultValue(predicateType, "InToto"), + setDefaultValue(key, "PGP"), + setDefaultValue(subjectRepoPath, subjectRepoPath), + setDefaultValue(releaseBundle, releaseBundle), + setDefaultValue(releaseBundleVersion, releaseBundleVersion), + }, + expectErr: true, + }, + { + name: "ValidContext - ReleaseBundle", + flags: []components.Flag{ + setDefaultValue(predicate, predicate), + setDefaultValue(predicateType, "InToto"), + setDefaultValue(key, "PGP"), + setDefaultValue(releaseBundle, releaseBundle), + setDefaultValue(releaseBundleVersion, releaseBundleVersion), + setDefaultValue("url", "url"), + }, + expectErr: false, + }, + { + name: "ValidContext - RepoPath", + flags: []components.Flag{ + setDefaultValue(predicate, predicate), + setDefaultValue(predicateType, "InToto"), + setDefaultValue(key, "PGP"), + setDefaultValue(subjectRepoPath, subjectRepoPath), + setDefaultValue("url", "url"), + }, + expectErr: false, + }, + { + name: "ValidContext - Build", + flags: []components.Flag{ + setDefaultValue(predicate, predicate), + setDefaultValue(predicateType, "InToto"), + setDefaultValue(key, "PGP"), + setDefaultValue(buildName, buildName), + setDefaultValue(buildNumber, buildNumber), + setDefaultValue("url", "url"), + }, + expectErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + context, err1 := components.ConvertContext(ctx, tt.flags...) + if err1 != nil { + return + } + + execFunc = func(command commands.Command) error { + return nil + } + // Replace execFunc with the mockExec function + defer func() { execFunc = exec }() // Restore original execFunc after test + + err := createEvidence(context) + if tt.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func setDefaultValue(flag string, defaultValue string) components.Flag { + f := components.NewStringFlag(flag, flag) + f.DefaultValue = defaultValue + return f +} diff --git a/evidence/cli/command_controller_test.go b/evidence/cli/command_controller_test.go deleted file mode 100644 index fd6c3c3..0000000 --- a/evidence/cli/command_controller_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package cli - -import ( - "github.com/golang/mock/gomock" - "github.com/jfrog/jfrog-cli-core/v2/common/commands" - "reflect" - "testing" - "unsafe" - - "github.com/jfrog/jfrog-cli-core/v2/plugins/components" - "github.com/stretchr/testify/assert" -) - -func TestCreateEvidence_Context(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - tests := []struct { - name string - context *components.Context - expectErr bool - }{ - { - name: "InvalidContext - Missing Subject", - context: createContext("somePredicate", "InToto", "PGP", "", ""), - expectErr: true, - }, - { - name: "InvalidContext - Missing Predicate", - context: createContext("", "InToto", "PGP", "someBundle", ""), - expectErr: true, - }, - { - name: "InvalidContext - Subject Duplication", - context: createContext("somePredicate", "InToto", "PGP", "someBundle", "path"), - expectErr: true, - }, - { - name: "ValidContext - ReleaseBundle", - context: createContext("somePredicate", "InToto", "PGP", "someBundle:1", ""), - expectErr: false, - }, - { - name: "ValidContext - RepoPath", - context: createContext("somePredicate", "InToto", "PGP", "", "path"), - expectErr: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - execFunc = func(command commands.Command) error { - return nil - } - - // Replace execFunc with the mockExec function - defer func() { execFunc = exec }() // Restore original execFunc after test - - err := createEvidence(tt.context) - if tt.expectErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -func createContext(predicate string, predicateType string, key string, rb string, repoPath string) *components.Context { - ctx := &components.Context{ - Arguments: []string{}, - } - setStringFlagValue(ctx, predicate, predicate) - setStringFlagValue(ctx, predicateType, predicateType) - setStringFlagValue(ctx, key, key) - setStringFlagValue(ctx, repoPath, repoPath) - setStringFlagValue(ctx, releaseBundle, rb) - return ctx -} - -func setStringFlagValue(ctx *components.Context, flagName, value string) { - val := reflect.ValueOf(ctx).Elem() - stringFlags := val.FieldByName("stringFlags") - - // If the field is not settable, we need to make it settable - if !stringFlags.CanSet() { - stringFlags = reflect.NewAt(stringFlags.Type(), unsafe.Pointer(stringFlags.UnsafeAddr())).Elem() - } - - if stringFlags.IsNil() { - stringFlags.Set(reflect.MakeMap(stringFlags.Type())) - } - stringFlags.SetMapIndex(reflect.ValueOf(flagName), reflect.ValueOf(value)) -} diff --git a/evidence/cli/command_custom.go b/evidence/cli/command_custom.go index 6a22566..914557a 100644 --- a/evidence/cli/command_custom.go +++ b/evidence/cli/command_custom.go @@ -17,14 +17,14 @@ func NewEvidenceCustomCommand(ctx *components.Context, execute execCommandFunc) execute: execute, } } - -func (ecc *evidenceCustomCommand) CreateEvidence(serverDetails *coreConfig.ServerDetails) error { +func (ecc *evidenceCustomCommand) CreateEvidence(_ *components.Context, serverDetails *coreConfig.ServerDetails) error { createCmd := evidence.NewCreateEvidenceCustom( serverDetails, ecc.ctx.GetStringFlagValue(predicate), ecc.ctx.GetStringFlagValue(predicateType), ecc.ctx.GetStringFlagValue(key), ecc.ctx.GetStringFlagValue(keyId), - ecc.ctx.GetStringFlagValue(repoPath)) + ecc.ctx.GetStringFlagValue(subjectRepoPath), + ecc.ctx.GetStringFlagValue(subjectSha256)) return ecc.execute(createCmd) } diff --git a/evidence/cli/command_relesae_bundle.go b/evidence/cli/command_relesae_bundle.go index 464bd7e..08fde8c 100644 --- a/evidence/cli/command_relesae_bundle.go +++ b/evidence/cli/command_relesae_bundle.go @@ -4,6 +4,7 @@ import ( "github.com/jfrog/jfrog-cli-artifactory/evidence" "github.com/jfrog/jfrog-cli-core/v2/plugins/components" coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-client-go/utils/errorutils" ) type evidenceReleaseBundleCommand struct { @@ -18,7 +19,12 @@ func NewEvidenceReleaseBundleCommand(ctx *components.Context, execute execComman } } -func (erc *evidenceReleaseBundleCommand) CreateEvidence(serverDetails *coreConfig.ServerDetails) error { +func (erc *evidenceReleaseBundleCommand) CreateEvidence(ctx *components.Context, serverDetails *coreConfig.ServerDetails) error { + err := erc.validateEvidenceReleaseBundleContext(ctx) + if err != nil { + return err + } + createCmd := evidence.NewCreateEvidenceReleaseBundle( serverDetails, erc.ctx.GetStringFlagValue(predicate), @@ -26,6 +32,14 @@ func (erc *evidenceReleaseBundleCommand) CreateEvidence(serverDetails *coreConfi erc.ctx.GetStringFlagValue(key), erc.ctx.GetStringFlagValue(keyId), erc.ctx.GetStringFlagValue(project), - erc.ctx.GetStringFlagValue(releaseBundle)) + erc.ctx.GetStringFlagValue(releaseBundle), + erc.ctx.GetStringFlagValue(releaseBundleVersion)) return erc.execute(createCmd) } + +func (erc *evidenceReleaseBundleCommand) validateEvidenceReleaseBundleContext(ctx *components.Context) error { + if !ctx.IsFlagSet(releaseBundleVersion) || assertValueProvided(ctx, releaseBundleVersion) != nil { + return errorutils.CheckErrorf("'releaseBundleVersion' is a mandatory field for creating a Release Bundle evidence: --%s", releaseBundleVersion) + } + return nil +} diff --git a/evidence/cli/flags.go b/evidence/cli/flags.go index 0cf036f..5bcbfaa 100644 --- a/evidence/cli/flags.go +++ b/evidence/cli/flags.go @@ -20,16 +20,19 @@ const ( project = "project" // RLM flags keys - releaseBundle = "release-bundle" - build = "build" + releaseBundle = "release-bundle" + releaseBundleVersion = "release-bundle-version" + buildName = "build-name" + buildNumber = "build-number" // Unique evidence flags - evidencePrefix = "evd-" - predicate = "predicate" - predicateType = "predicate-type" - repoPath = "repo-path" - key = "key" - keyId = "key-name" + evidencePrefix = "evd-" + predicate = "predicate" + predicateType = "predicate-type" + subjectRepoPath = "subject-repo-path" + subjectSha256 = "subject-sha256" + key = "key" + keyId = "key-name" ) // Flag keys mapped to their corresponding components.Flag definition. @@ -42,19 +45,37 @@ var flagsMap = map[string]components.Flag{ accessToken: components.NewStringFlag(accessToken, "JFrog access token.", func(f *components.StringFlag) { f.Mandatory = false }), project: components.NewStringFlag(project, "Project key associated with the created evidence.", func(f *components.StringFlag) { f.Mandatory = false }), - releaseBundle: components.NewStringFlag(releaseBundle, "Release Bundle name and version. Format: :", func(f *components.StringFlag) { f.Mandatory = false }), - build: components.NewStringFlag(build, "Build name and number. Format: :", func(f *components.StringFlag) { f.Mandatory = false }), + releaseBundle: components.NewStringFlag(releaseBundle, "Release Bundle name.", func(f *components.StringFlag) { f.Mandatory = false }), + releaseBundleVersion: components.NewStringFlag(releaseBundleVersion, "Release Bundle version.", func(f *components.StringFlag) { f.Mandatory = false }), + buildName: components.NewStringFlag(buildName, "Build name.", func(f *components.StringFlag) { f.Mandatory = false }), + buildNumber: components.NewStringFlag(buildNumber, "Build number.", func(f *components.StringFlag) { f.Mandatory = false }), - predicate: components.NewStringFlag(predicate, "Path to the predicate, arbitrary JSON.", func(f *components.StringFlag) { f.Mandatory = true }), - predicateType: components.NewStringFlag(predicateType, "Type of the predicate.", func(f *components.StringFlag) { f.Mandatory = true }), - repoPath: components.NewStringFlag(repoPath, "Full path to some artifact' location.", func(f *components.StringFlag) { f.Mandatory = false }), - key: components.NewStringFlag(key, "Path to a private key that will sign the DSSE. Supported keys: 'ecdsa','rsa' and 'ed25519'.", func(f *components.StringFlag) { f.Mandatory = true }), - keyId: components.NewStringFlag(keyId, "KeyId", func(f *components.StringFlag) { f.Mandatory = false }), + predicate: components.NewStringFlag(predicate, "Path to the predicate, arbitrary JSON.", func(f *components.StringFlag) { f.Mandatory = true }), + predicateType: components.NewStringFlag(predicateType, "Type of the predicate.", func(f *components.StringFlag) { f.Mandatory = true }), + subjectRepoPath: components.NewStringFlag(subjectRepoPath, "Full path to some subject' location.", func(f *components.StringFlag) { f.Mandatory = false }), + subjectSha256: components.NewStringFlag(subjectSha256, "subject checksum sha256.", func(f *components.StringFlag) { f.Mandatory = false }), + key: components.NewStringFlag(key, "Path to a private key that will sign the DSSE. Supported keys: 'ecdsa','rsa' and 'ed25519'.", func(f *components.StringFlag) { f.Mandatory = true }), + keyId: components.NewStringFlag(keyId, "KeyId", func(f *components.StringFlag) { f.Mandatory = false }), } var commandFlags = map[string][]string{ CreateEvidence: { - url, user, password, accessToken, ServerId, project, releaseBundle, build, predicate, predicateType, repoPath, key, keyId, + url, + user, + password, + accessToken, + ServerId, + project, + releaseBundle, + releaseBundleVersion, + buildName, + buildNumber, + predicate, + predicateType, + subjectRepoPath, + subjectSha256, + key, + keyId, }, } diff --git a/evidence/cli/utils.go b/evidence/cli/utils.go index f1ce84c..6219f4d 100644 --- a/evidence/cli/utils.go +++ b/evidence/cli/utils.go @@ -9,7 +9,7 @@ func exec(command commands.Command) error { } var subjectTypes = []string{ - repoPath, + subjectRepoPath, releaseBundle, - build, + buildName, } diff --git a/evidence/create_base.go b/evidence/create_base.go index c2c5910..4004b7c 100644 --- a/evidence/create_base.go +++ b/evidence/create_base.go @@ -26,8 +26,8 @@ type createEvidenceBase struct { keyId string } -func (c *createEvidenceBase) createEnvelope(subject string) ([]byte, error) { - statementJson, err := c.buildIntotoStatementJson(subject) +func (c *createEvidenceBase) createEnvelope(subject, subjectSha256 string) ([]byte, error) { + statementJson, err := c.buildIntotoStatementJson(subject, subjectSha256) if err != nil { return nil, err } @@ -45,7 +45,7 @@ func (c *createEvidenceBase) createEnvelope(subject string) ([]byte, error) { return envelopeBytes, nil } -func (c *createEvidenceBase) buildIntotoStatementJson(subject string) ([]byte, error) { +func (c *createEvidenceBase) buildIntotoStatementJson(subject, subjectSha256 string) ([]byte, error) { predicate, err := os.ReadFile(c.predicateFilePath) if err != nil { log.Warn(fmt.Sprintf("failed to read predicate file '%s'", predicate)) @@ -58,7 +58,7 @@ func (c *createEvidenceBase) buildIntotoStatementJson(subject string) ([]byte, e } statement := intoto.NewStatement(predicate, c.predicateType, c.serverDetails.User) - err = statement.SetSubject(artifactoryClient, subject) + err = statement.SetSubject(artifactoryClient, subject, subjectSha256) if err != nil { return nil, err } diff --git a/evidence/create_build.go b/evidence/create_build.go index fd60cc2..ee88ef7 100644 --- a/evidence/create_build.go +++ b/evidence/create_build.go @@ -9,17 +9,17 @@ import ( "github.com/jfrog/jfrog-client-go/artifactory/services" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/log" - "strings" ) type createEvidenceBuild struct { createEvidenceBase - project string - build string + project string + buildName string + buildNumber string } func NewCreateEvidenceBuild(serverDetails *coreConfig.ServerDetails, - predicateFilePath, predicateType, key, keyId, project, build string) Command { + predicateFilePath, predicateType, key, keyId, project, buildName, buildNumber string) Command { return &createEvidenceBuild{ createEvidenceBase: createEvidenceBase{ serverDetails: serverDetails, @@ -28,13 +28,14 @@ func NewCreateEvidenceBuild(serverDetails *coreConfig.ServerDetails, key: key, keyId: keyId, }, - project: project, - build: build, + project: project, + buildName: buildName, + buildNumber: buildNumber, } } func (c *createEvidenceBuild) CommandName() string { - return "create-build-evidence" + return "create-buildName-evidence" } func (c *createEvidenceBuild) ServerDetails() (*config.ServerDetails, error) { @@ -47,11 +48,11 @@ func (c *createEvidenceBuild) Run() error { log.Error("failed to create Artifactory client", err) return err } - subject, err := c.buildBuildInfoSubjectPath(artifactoryClient) + subject, sha256, err := c.buildBuildInfoSubjectPath(artifactoryClient) if err != nil { return err } - envelope, err := c.createEnvelope(subject) + envelope, err := c.createEnvelope(subject, sha256) if err != nil { return err } @@ -63,26 +64,19 @@ func (c *createEvidenceBuild) Run() error { return nil } -func (c *createEvidenceBuild) buildBuildInfoSubjectPath(artifactoryClient artifactory.ArtifactoryServicesManager) (string, error) { - build := strings.Split(c.build, ":") - if len(build) != 2 { - return "", fmt.Errorf("invalid build format. expected format is :") - } - name := build[0] - number := build[1] - - timestamp, err := getBuildLatestTimestamp(name, number, c.project, artifactoryClient) +func (c *createEvidenceBuild) buildBuildInfoSubjectPath(artifactoryClient artifactory.ArtifactoryServicesManager) (string, string, error) { + timestamp, err := getBuildLatestTimestamp(c.buildName, c.buildNumber, c.project, artifactoryClient) if err != nil { - return "", err + return "", "", err } repoKey := buildBuildInfoRepoKey(c.project) - buildInfoPath := buildBuildInfoPath(repoKey, name, number, timestamp) + buildInfoPath := buildBuildInfoPath(repoKey, c.buildName, c.buildNumber, timestamp) buildInfoChecksum, err := getBuildInfoPathChecksum(buildInfoPath, artifactoryClient) if err != nil { - return "", err + return "", "", err } - return buildInfoPath + "@" + buildInfoChecksum, nil + return buildInfoPath, buildInfoChecksum, nil } func getBuildLatestTimestamp(name string, number string, project string, artifactoryClient artifactory.ArtifactoryServicesManager) (string, error) { @@ -96,7 +90,7 @@ func getBuildLatestTimestamp(name string, number string, project string, artifac return "", err } if !ok { - errorMessage := fmt.Sprintf("failed to find build, name:%s, number:%s, project: %s", name, number, project) + errorMessage := fmt.Sprintf("failed to find buildName, name:%s, number:%s, project: %s", name, number, project) return "", errorutils.CheckErrorf(errorMessage) } timestamp, err := utils.ParseIsoTimestamp(res.BuildInfo.Started) @@ -121,7 +115,7 @@ func buildBuildInfoPath(repoKey string, name string, number string, timestamp st func getBuildInfoPathChecksum(buildInfoPath string, artifactoryClient artifactory.ArtifactoryServicesManager) (string, error) { res, err := artifactoryClient.FileInfo(buildInfoPath) if err != nil { - log.Warn(fmt.Sprintf("build info json path '%s' does not exist.", buildInfoPath)) + log.Warn(fmt.Sprintf("buildName info json path '%s' does not exist.", buildInfoPath)) return "", err } return res.Checksums.Sha256, nil diff --git a/evidence/create_build_test.go b/evidence/create_build_test.go index 3b39f77..2c89a97 100644 --- a/evidence/create_build_test.go +++ b/evidence/create_build_test.go @@ -40,49 +40,51 @@ func (m *mockArtifactoryServicesManagerBuild) GetBuildInfo(services.BuildInfoPar func TestBuildInfo(t *testing.T) { tests := []struct { - name string - project string - build string - expectedPath string - expectError bool + name string + project string + buildName string + buildNumber string + expectedPath string + expectedChecksum string + expectError bool }{ { - name: "Valid build with project", - project: "myProject", - build: "buildName:1", - expectedPath: "myProject-build-info/buildName/1-1705529045000.json@dummy_sha256", - expectError: false, + name: "Valid buildName with project", + project: "myProject", + buildName: "buildName", + buildNumber: "1", + expectedPath: "myProject-build-info/buildName/1-1705529045000.json", + expectedChecksum: "dummy_sha256", + expectError: false, }, { - name: "Valid build default project", - project: "default", - build: "buildName:1", - expectedPath: "artifactory-build-info/buildName/1-1705529045000.json@dummy_sha256", - expectError: false, - }, - { - name: "Invalid build format", - project: "myProject", - build: "buildName-1", - expectedPath: "", - expectError: true, + name: "Valid buildName default project", + project: "default", + buildName: "buildName", + buildNumber: "1", + expectedPath: "artifactory-build-info/buildName/1-1705529045000.json", + expectedChecksum: "dummy_sha256", + expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &createEvidenceBuild{ - project: tt.project, - build: tt.build, + project: tt.project, + buildName: tt.buildName, + buildNumber: tt.buildNumber, } aa := &mockArtifactoryServicesManagerBuild{} - path, err := c.buildBuildInfoSubjectPath(aa) + path, sha256, err := c.buildBuildInfoSubjectPath(aa) if tt.expectError { assert.Error(t, err) assert.Empty(t, path) + assert.Empty(t, sha256) } else { assert.NoError(t, err) assert.Equal(t, tt.expectedPath, path) + assert.Equal(t, tt.expectedChecksum, sha256) } }) } diff --git a/evidence/create_custom.go b/evidence/create_custom.go index 1629c8f..68b9b64 100644 --- a/evidence/create_custom.go +++ b/evidence/create_custom.go @@ -7,11 +7,12 @@ import ( type createEvidenceCustom struct { createEvidenceBase - repoPath string + subjectRepoPath string + subjectSha256 string } -func NewCreateEvidenceCustom(serverDetails *coreConfig.ServerDetails, predicateFilePath string, predicateType string, key string, keyId string, - repoPath string) Command { +func NewCreateEvidenceCustom(serverDetails *coreConfig.ServerDetails, predicateFilePath, predicateType, key, keyId, subjectRepoPath, + subjectSha256 string) Command { return &createEvidenceCustom{ createEvidenceBase: createEvidenceBase{ serverDetails: serverDetails, @@ -20,7 +21,8 @@ func NewCreateEvidenceCustom(serverDetails *coreConfig.ServerDetails, predicateF key: key, keyId: keyId, }, - repoPath: repoPath, + subjectRepoPath: subjectRepoPath, + subjectSha256: subjectSha256, } } @@ -33,11 +35,11 @@ func (c *createEvidenceCustom) ServerDetails() (*config.ServerDetails, error) { } func (c *createEvidenceCustom) Run() error { - envelope, err := c.createEnvelope(c.repoPath) + envelope, err := c.createEnvelope(c.subjectRepoPath, c.subjectSha256) if err != nil { return err } - err = c.uploadEvidence(envelope, c.repoPath) + err = c.uploadEvidence(envelope, c.subjectRepoPath) if err != nil { return err } diff --git a/evidence/create_release_bundle.go b/evidence/create_release_bundle.go index e2fb230..8a5101b 100644 --- a/evidence/create_release_bundle.go +++ b/evidence/create_release_bundle.go @@ -6,17 +6,17 @@ import ( coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-client-go/artifactory" "github.com/jfrog/jfrog-client-go/utils/log" - "strings" ) type createEvidenceReleaseBundle struct { createEvidenceBase - project string - releaseBundle string + project string + releaseBundle string + releaseBundleVersion string } -func NewCreateEvidenceReleaseBundle(serverDetails *coreConfig.ServerDetails, predicateFilePath string, predicateType string, key string, keyId string, - project string, releaseBundle string) Command { +func NewCreateEvidenceReleaseBundle(serverDetails *coreConfig.ServerDetails, predicateFilePath, predicateType, key, keyId, project, releaseBundle, + releaseBundleVersion string) Command { return &createEvidenceReleaseBundle{ createEvidenceBase: createEvidenceBase{ serverDetails: serverDetails, @@ -25,8 +25,9 @@ func NewCreateEvidenceReleaseBundle(serverDetails *coreConfig.ServerDetails, pre key: key, keyId: keyId, }, - project: project, - releaseBundle: releaseBundle, + project: project, + releaseBundle: releaseBundle, + releaseBundleVersion: releaseBundleVersion, } } @@ -44,11 +45,11 @@ func (c *createEvidenceReleaseBundle) Run() error { log.Error("failed to create Artifactory client", err) return err } - subject, err := c.buildReleaseBundleSubjectPath(artifactoryClient) + subject, sha256, err := c.buildReleaseBundleSubjectPath(artifactoryClient) if err != nil { return err } - envelope, err := c.createEnvelope(subject) + envelope, err := c.createEnvelope(subject, sha256) if err != nil { return err } @@ -60,22 +61,16 @@ func (c *createEvidenceReleaseBundle) Run() error { return nil } -func (c *createEvidenceReleaseBundle) buildReleaseBundleSubjectPath(artifactoryClient artifactory.ArtifactoryServicesManager) (string, error) { - releaseBundle := strings.Split(c.releaseBundle, ":") - if len(releaseBundle) != 2 { - return "", fmt.Errorf("invalid release bundle format. expected format is :") - } - name := releaseBundle[0] - version := releaseBundle[1] +func (c *createEvidenceReleaseBundle) buildReleaseBundleSubjectPath(artifactoryClient artifactory.ArtifactoryServicesManager) (string, string, error) { repoKey := buildRepoKey(c.project) - manifestPath := buildManifestPath(repoKey, name, version) + manifestPath := buildManifestPath(repoKey, c.releaseBundle, c.releaseBundleVersion) manifestChecksum, err := getManifestPathChecksum(manifestPath, artifactoryClient) if err != nil { - return "", err + return "", "", err } - return manifestPath + "@" + manifestChecksum, nil + return manifestPath, manifestChecksum, nil } func buildRepoKey(project string) string { diff --git a/evidence/create_release_bundle_test.go b/evidence/create_release_bundle_test.go index 5653665..fa20f40 100644 --- a/evidence/create_release_bundle_test.go +++ b/evidence/create_release_bundle_test.go @@ -29,63 +29,60 @@ func (m *mockReleaseBundleArtifactoryServicesManager) FileInfo(relativePath stri func TestReleaseBundle(t *testing.T) { tests := []struct { - name string - project string - releaseBundle string - expectedPath string - expectError bool + name string + project string + releaseBundle string + releaseBundleVersion string + expectedPath string + expectedCheckSum string + expectError bool }{ { - name: "Valid release bundle with project", - project: "myProject", - releaseBundle: "bundleName:1.0.0", - expectedPath: "myProject-release-bundles-v2/bundleName/1.0.0/release-bundle.json.evd@dummy_sha256", - expectError: false, + name: "Valid release bundle with project", + project: "myProject", + releaseBundle: "bundleName", + releaseBundleVersion: "1.0.0", + expectedPath: "myProject-release-bundles-v2/bundleName/1.0.0/release-bundle.json.evd", + expectedCheckSum: "dummy_sha256", + expectError: false, }, { - name: "Valid release bundle default project", - project: "default", - releaseBundle: "bundleName:1.0.0", - expectedPath: "release-bundles-v2/bundleName/1.0.0/release-bundle.json.evd@dummy_sha256", - expectError: false, + name: "Valid release bundle default project", + project: "default", + releaseBundle: "bundleName", + releaseBundleVersion: "1.0.0", + expectedPath: "release-bundles-v2/bundleName/1.0.0/release-bundle.json.evd", + expectedCheckSum: "dummy_sha256", + expectError: false, }, { - name: "Valid release bundle empty project", - project: "default", - releaseBundle: "bundleName:1.0.0", - expectedPath: "release-bundles-v2/bundleName/1.0.0/release-bundle.json.evd@dummy_sha256", - expectError: false, - }, - { - name: "Invalid release bundle format 1", - project: "myProject", - releaseBundle: "bundleName:1.0.0:111", - expectedPath: "", - expectError: true, - }, - { - name: "Invalid release bundle format 2", - project: "myProject", - releaseBundle: "bundleName111", - expectedPath: "", - expectError: true, + name: "Valid release bundle empty project", + project: "default", + releaseBundle: "bundleName", + releaseBundleVersion: "1.0.0", + expectedPath: "release-bundles-v2/bundleName/1.0.0/release-bundle.json.evd", + expectedCheckSum: "dummy_sha256", + expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &createEvidenceReleaseBundle{ - project: tt.project, - releaseBundle: tt.releaseBundle, + project: tt.project, + releaseBundle: tt.releaseBundle, + releaseBundleVersion: tt.releaseBundleVersion, } aa := &mockReleaseBundleArtifactoryServicesManager{} - path, err := c.buildReleaseBundleSubjectPath(aa) + path, sha256, err := c.buildReleaseBundleSubjectPath(aa) if tt.expectError { assert.Error(t, err) + assert.Empty(t, sha256) assert.Empty(t, path) } else { assert.NoError(t, err) assert.Equal(t, tt.expectedPath, path) + assert.Equal(t, tt.expectedCheckSum, sha256) } }) } diff --git a/evidence/intoto/intoto_statement_v1.go b/evidence/intoto/intoto_statement_v1.go index 1d888d7..cb60c81 100644 --- a/evidence/intoto/intoto_statement_v1.go +++ b/evidence/intoto/intoto_statement_v1.go @@ -3,7 +3,6 @@ package intoto import ( "encoding/json" "github.com/jfrog/jfrog-client-go/utils/errorutils" - "strings" "time" "github.com/jfrog/jfrog-client-go/artifactory" @@ -42,18 +41,13 @@ func NewStatement(predicate []byte, predicateType string, user string) *Statemen } } -func (s *Statement) SetSubject(servicesManager artifactory.ArtifactoryServicesManager, subject string) error { - subjectAndSha := strings.Split(subject, "@") +func (s *Statement) SetSubject(servicesManager artifactory.ArtifactoryServicesManager, subject, subjectSha256 string) error { s.Subject = make([]ResourceDescriptor, 1) - if len(subjectAndSha) > 1 { - s.Subject[0].Digest.Sha256 = subjectAndSha[1] - } - - res, err := servicesManager.FileInfo(subjectAndSha[0]) + res, err := servicesManager.FileInfo(subject) if err != nil { return err } - if s.Subject[0].Digest.Sha256 != "" && res.Checksums.Sha256 != s.Subject[0].Digest.Sha256 { + if subjectSha256 != "" && res.Checksums.Sha256 != subjectSha256 { return errorutils.CheckErrorf("provided sha256 does not match the file's sha256") } s.Subject[0].Digest.Sha256 = res.Checksums.Sha256 diff --git a/evidence/intoto/intoto_statement_v1_test.go b/evidence/intoto/intoto_statement_v1_test.go index 3c1ead7..4192bbf 100644 --- a/evidence/intoto/intoto_statement_v1_test.go +++ b/evidence/intoto/intoto_statement_v1_test.go @@ -47,7 +47,7 @@ func TestSetSubjectSha256NotEqual(t *testing.T) { st := NewStatement([]byte(predicate), predicateType, "") assert.NotNil(t, st) aa := &mockArtifactoryServicesManager{} - err := st.SetSubject(aa, "path/to/file.txt@e77779f5a976c7f4a5406907790bb8cad6148406282f07cd143fd1de64ca169d") + err := st.SetSubject(aa, "path/to/file.txt", "e77779f5a976c7f4a5406907790bb8cad6148406282f07cd143fd1de64ca169d") assert.Error(t, err) } @@ -57,7 +57,7 @@ func TestSetSubjectSha256Equal(t *testing.T) { st := NewStatement([]byte(predicate), predicateType, "") assert.NotNil(t, st) aa := &mockArtifactoryServicesManager{} - err := st.SetSubject(aa, "path/to/file.txt@e06f59f5a976c7f4a5406907790bb8cad6148406282f07cd143fd1de64ca169d") + err := st.SetSubject(aa, "path/to/file.txt", "e06f59f5a976c7f4a5406907790bb8cad6148406282f07cd143fd1de64ca169d") assert.NoError(t, err) } diff --git a/go.mod b/go.mod index 19229cc..f21f4ce 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,15 @@ module github.com/jfrog/jfrog-cli-artifactory go 1.22.3 require ( + github.com/golang/mock v1.6.0 + github.com/jfrog/build-info-go v1.9.29 + github.com/jfrog/gofrog v1.7.4 github.com/jfrog/jfrog-cli-core/v2 v2.53.3 github.com/jfrog/jfrog-client-go v1.42.0 github.com/pkg/errors v0.9.1 github.com/secure-systems-lab/go-securesystemslib v0.8.0 github.com/stretchr/testify v1.9.0 + github.com/urfave/cli v1.22.15 ) require ( @@ -40,8 +44,6 @@ require ( github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jedib0t/go-pretty/v6 v6.5.9 // indirect github.com/jfrog/archiver/v3 v3.6.1 // indirect - github.com/jfrog/build-info-go v1.9.29 // indirect - github.com/jfrog/gofrog v1.7.4 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.3 // indirect @@ -74,7 +76,6 @@ require ( github.com/spf13/viper v1.19.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/ulikunitz/xz v0.5.12 // indirect - github.com/urfave/cli v1.22.15 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect diff --git a/go.sum b/go.sum index d714f8d..03ca569 100644 --- a/go.sum +++ b/go.sum @@ -73,6 +73,8 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -220,12 +222,14 @@ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofm github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -234,12 +238,15 @@ golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= @@ -249,6 +256,7 @@ golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= @@ -256,6 +264,7 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -265,7 +274,9 @@ golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -298,11 +309,14 @@ golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=