diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index d8eed7c..b43ac98 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -39,4 +39,4 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 with: - version: v2.11 + version: v2.12 diff --git a/.golangci.yaml b/.golangci.yaml index 4099eb2..f42d5a3 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -60,7 +60,7 @@ linters: - godox - goheader - gomoddirectives - - gomodguard + - gomodguard_v2 - goprintffuncname - gosec - gosmopolitan @@ -110,6 +110,9 @@ linters: - zerologlint settings: + goconst: + # Repeated literals in table driven tests don't warrant constants. + ignore-tests: true gocyclo: min-complexity: 35 godox: diff --git a/internal/cmd/audit.go b/internal/cmd/audit.go index 1ce3e93..08a32fe 100644 --- a/internal/cmd/audit.go +++ b/internal/cmd/audit.go @@ -23,6 +23,9 @@ const ( const ( statusPassed = "passed" statusFailed = "failed" + + auditModeBasicName = "basic" + auditModeFullName = "full" ) // Enable audit mode enum @@ -30,9 +33,9 @@ const ( func (e *AuditMode) String() string { switch *e { case AuditModeBasic: - return "basic" + return auditModeBasicName case AuditModeFull: - return "full" + return auditModeFullName } return "error" } @@ -40,14 +43,14 @@ func (e *AuditMode) String() string { // Set must have pointer receiver so it doesn't change the value of a copy func (e *AuditMode) Set(v string) error { switch v { - case "basic": + case auditModeBasicName: *e = AuditModeBasic return nil - case "full": + case auditModeFullName: *e = AuditModeFull return nil default: - return errors.New(`must be one of "foo", "bar", or "moo"`) + return fmt.Errorf("must be one of %q or %q", auditModeBasicName, auditModeFullName) } } @@ -119,7 +122,7 @@ func addAudit(parentCmd *cobra.Command) { opts := &auditOpts{} auditCmd := &cobra.Command{ Use: "audit", - GroupID: "verification", + GroupID: cmdGroupVerification, Short: "Verifies multiple commits in the branch history", Long: `Checks the revisions on the specified branch within the repository. diff --git a/internal/cmd/auth.go b/internal/cmd/auth.go index c258d07..525d9d4 100644 --- a/internal/cmd/auth.go +++ b/internal/cmd/auth.go @@ -18,7 +18,7 @@ var colorHiRed = color.New(color.FgHiRed).SprintFunc() func addAuth(parentCmd *cobra.Command) { authCmd := &cobra.Command{ - GroupID: "configuration", + GroupID: cmdGroupConfiguration, Short: "Manage user authentication", Use: "auth", SilenceUsage: false, diff --git a/internal/cmd/checklevel.go b/internal/cmd/checklevel.go index a8a4520..be8c3e6 100644 --- a/internal/cmd/checklevel.go +++ b/internal/cmd/checklevel.go @@ -44,7 +44,7 @@ func addCheckLevel(parentCmd *cobra.Command) { checklevelCmd := &cobra.Command{ Use: "checklevel", - GroupID: "assessment", + GroupID: cmdGroupAssessment, Short: "Determines the SLSA Source Level of the repo", Long: `Determines the SLSA Source Level of the repo. diff --git a/internal/cmd/checklevelprov.go b/internal/cmd/checklevelprov.go index de6ca3e..96643ca 100644 --- a/internal/cmd/checklevelprov.go +++ b/internal/cmd/checklevelprov.go @@ -89,7 +89,7 @@ func addCheckLevelProv(parentCmd *cobra.Command) { checklevelprovCmd := &cobra.Command{ Use: "checklevelprov", - GroupID: "assessment", + GroupID: cmdGroupAssessment, Example: `sourcetool checklevelprov owner/repo --push=note`, Short: "Checks the given commit against policy using & creating provenance", Long: `Checks the given commit against policy using & creating provenance. diff --git a/internal/cmd/checktag.go b/internal/cmd/checktag.go index 0e3154f..fa1b28c 100644 --- a/internal/cmd/checktag.go +++ b/internal/cmd/checktag.go @@ -55,7 +55,7 @@ func addCheckTag(parentCmd *cobra.Command) { checktagCmd := &cobra.Command{ Use: "checktag", - GroupID: "assessment", + GroupID: cmdGroupAssessment, Short: "Checks to see if the tag operation should be allowed and issues a VSA", PreRunE: func(cmd *cobra.Command, args []string) error { if len(args) > 0 { diff --git a/internal/cmd/createpolicy.go b/internal/cmd/createpolicy.go index 101592b..8f87f3f 100644 --- a/internal/cmd/createpolicy.go +++ b/internal/cmd/createpolicy.go @@ -31,7 +31,7 @@ func addCreatePolicy(parentCmd *cobra.Command) { createpolicyCmd := &cobra.Command{ Use: "createpolicy", - GroupID: "policy", + GroupID: cmdGroupPolicy, Short: "Creates a policy in a local copy of source-policies", Long: `Creates a SLSA source policy in a local copy of source-policies. diff --git a/internal/cmd/policy.go b/internal/cmd/policy.go index b0da20b..1751fa8 100644 --- a/internal/cmd/policy.go +++ b/internal/cmd/policy.go @@ -39,7 +39,7 @@ func (pco *policyCreateOpts) AddFlags(cmd *cobra.Command) { func addPolicy(parentCmd *cobra.Command) { policyCmd := &cobra.Command{ - GroupID: "policy", + GroupID: cmdGroupPolicy, Short: "tools to work with source policies", Long: fmt.Sprintf(` %s %s diff --git a/internal/cmd/prov.go b/internal/cmd/prov.go index 1555c2c..0da64ce 100644 --- a/internal/cmd/prov.go +++ b/internal/cmd/prov.go @@ -39,7 +39,7 @@ func addProv(parentCmd *cobra.Command) { opts := provOptions{} provCmd := &cobra.Command{ Use: "prov", - GroupID: "assessment", + GroupID: cmdGroupAssessment, Short: "Creates provenance for the given commit, but does not check policy.", PreRunE: func(cmd *cobra.Command, args []string) error { if len(args) > 0 { diff --git a/internal/cmd/root.go b/internal/cmd/root.go index a395c19..5713652 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -15,16 +15,13 @@ import ( var githubToken string -// func getVerifier(vo *verifierOptions) attest.Verifier { -// options := attest.DefaultVerifierOptions -// if vo.expectedIssuer != "" { -// options.ExpectedIssuer = vo.expectedIssuer -// } -// if vo.expectedSan != "" { -// options.ExpectedSan = vo.expectedSan -// } -// return attest.NewBndVerifier(options) -// } +// Command group IDs used to organize the subcommands in the help screen. +const ( + cmdGroupVerification = "verification" + cmdGroupAssessment = "assessment" + cmdGroupPolicy = "policy" + cmdGroupConfiguration = "configuration" +) // exitError wraps an error together with an exit code so commands can // signal other failuresdistinct from a generic failure (exit 1). @@ -58,19 +55,19 @@ controls and much more. // Define command groups for better organization rootCmd.AddGroup( &cobra.Group{ - ID: "verification", + ID: cmdGroupVerification, Title: "Verification Commands:", }, &cobra.Group{ - ID: "assessment", + ID: cmdGroupAssessment, Title: "Assessment Commands:", }, &cobra.Group{ - ID: "policy", + ID: cmdGroupPolicy, Title: "Policy Commands:", }, &cobra.Group{ - ID: "configuration", + ID: cmdGroupConfiguration, Title: "Configuration & Setup Commands:", }, ) diff --git a/internal/cmd/setup.go b/internal/cmd/setup.go index f966c6a..7d15520 100644 --- a/internal/cmd/setup.go +++ b/internal/cmd/setup.go @@ -52,7 +52,7 @@ func (so *setupOpts) Validate() error { func addSetup(parentCmd *cobra.Command) { setupCmd := &cobra.Command{ - GroupID: "configuration", + GroupID: cmdGroupConfiguration, Short: "configure SLSA source features in a repository", Long: fmt.Sprintf(` %s %s diff --git a/internal/cmd/status.go b/internal/cmd/status.go index ff080ae..9d0cad4 100644 --- a/internal/cmd/status.go +++ b/internal/cmd/status.go @@ -47,7 +47,7 @@ func (so *statusOptions) AddFlags(cmd *cobra.Command) { func addStatus(parentCmd *cobra.Command) { opts := &statusOptions{} statusCmd := &cobra.Command{ - GroupID: "assessment", + GroupID: cmdGroupAssessment, Short: "Check the SLSA Source status of a repo/branch", Long: ` sourcetool status: Check the SLSA Source status of a repo/branch diff --git a/internal/cmd/verifycommit.go b/internal/cmd/verifycommit.go index 6bc4982..4645185 100644 --- a/internal/cmd/verifycommit.go +++ b/internal/cmd/verifycommit.go @@ -18,6 +18,12 @@ type verifyCommitOptions struct { revisionOpts } +// Ref types reported in the verification results +const ( + refTypeBranch = "branch" + refTypeTag = "tag" +) + // VerifyCommitResult represents the result of a commit verification type VerifyCommitResult struct { Success bool `json:"success"` @@ -58,7 +64,7 @@ func addVerifyCommit(cmd *cobra.Command) { opts := verifyCommitOptions{} verifyCommitCmd := &cobra.Command{ Use: "verifycommit", - GroupID: "verification", + GroupID: cmdGroupVerification, Short: "Verifies the specified commit is valid", PreRunE: func(cmd *cobra.Command, args []string) error { if len(args) > 0 { @@ -101,10 +107,10 @@ func addVerifyCommit(cmd *cobra.Command) { var refName string switch { case opts.branch != "": - refType = "branch" + refType = refTypeBranch refName = opts.branch case opts.tag != "": - refType = "tag" + refType = refTypeTag refName = opts.tag default: return fmt.Errorf("must specify either branch or tag") diff --git a/pkg/attest/attester.go b/pkg/attest/attester.go index 2e0a42a..07a26aa 100644 --- a/pkg/attest/attester.go +++ b/pkg/attest/attester.go @@ -206,7 +206,7 @@ func addPredToStatement(provPred proto.Message, predicateType, commit string) (* } sub := []*intoto.ResourceDescriptor{{ - Digest: map[string]string{"gitCommit": commit}, + Digest: map[string]string{models.DigestTypeGitCommit: commit}, }} var predPb structpb.Struct diff --git a/pkg/attest/statement.go b/pkg/attest/statement.go index 979bf0e..b8409bb 100644 --- a/pkg/attest/statement.go +++ b/pkg/attest/statement.go @@ -48,12 +48,12 @@ func GetSubjectForCommit(att attestation.Envelope, commit *models.Commit) *intot if !ok { continue } - val, ok := rd.GetDigest()["gitCommit"] + val, ok := rd.GetDigest()[models.DigestTypeGitCommit] if ok && val == commit.SHA { return rd } - if val, ok = rd.GetDigest()["sha1"]; ok && val == commit.SHA { + if val, ok = rd.GetDigest()[models.DigestTypeSha1]; ok && val == commit.SHA { fromSha = rd } } diff --git a/pkg/attest/vsa.go b/pkg/attest/vsa.go index bdff404..dcab259 100644 --- a/pkg/attest/vsa.go +++ b/pkg/attest/vsa.go @@ -51,7 +51,7 @@ func createUnsignedSourceVsaAllParams(branch *models.Branch, commit *models.Comm return "", fmt.Errorf("creating struct from map: %w", err) } sub := []*spb.ResourceDescriptor{{ - Digest: map[string]string{"gitCommit": commit.SHA}, + Digest: map[string]string{models.DigestTypeGitCommit: commit.SHA}, Annotations: annotationStruct, }} diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index 8bab65d..766228e 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -34,6 +34,10 @@ const ( SourcePolicyUri = "github.com/slsa-framework/source-policies" SourcePolicyRepoOwner = "slsa-framework" SourcePolicyRepo = "source-policies" + + // DefaultPolicyPath is the policy path reported when a branch is + // evaluated using the default policy. + DefaultPolicyPath = "DEFAULT" ) // Returns the policy for the branch or nil if the branch doesn't have one. @@ -635,7 +639,7 @@ func (pe *PolicyEvaluator) EvaluateControl(ctx context.Context, repo *models.Rep branchPolicy := rp.GetBranchPolicy(branch.Name) if branchPolicy == nil { branchPolicy = createDefaultBranchPolicy(branch) - policyPath = "DEFAULT" + policyPath = DefaultPolicyPath } if controlStatus.Time.Before(branchPolicy.GetSince().AsTime()) { @@ -675,7 +679,7 @@ func (pe *PolicyEvaluator) EvaluateSourceProv(ctx context.Context, repo *models. branchPolicy := rp.GetBranchPolicy(branch.Name) if branchPolicy == nil { branchPolicy = createDefaultBranchPolicy(branch) - policyPath = "DEFAULT" + policyPath = DefaultPolicyPath } verifiedLevels, shortfall, err := evaluateBranchControls(branchPolicy, rp.GetProtectedTag(), slsa.NewControlSetFromProvanenaceControls(provPred.GetControls())) diff --git a/pkg/sourcetool/implementation.go b/pkg/sourcetool/implementation.go index be395c4..89acec5 100644 --- a/pkg/sourcetool/implementation.go +++ b/pkg/sourcetool/implementation.go @@ -119,7 +119,7 @@ func (impl *defaultToolImplementation) CreatePolicyPR(a *auth.Authenticator, opt } policyRepo := &models.Repository{ - Hostname: "github.com", + Hostname: githubHostname, Path: fmt.Sprintf("%s/%s", policyRepoOwner, policyRepoName), DefaultBranch: "main", } @@ -163,7 +163,7 @@ func (impl *defaultToolImplementation) CheckForks(opts *options.Options) error { func (impl *defaultToolImplementation) CheckPolicyFork(opts *options.Options) error { manager := repo.NewPullRequestManager() if _, err := manager.CheckFork(&models.Repository{ - Hostname: "github.com", Path: opts.PolicyRepo, + Hostname: githubHostname, Path: opts.PolicyRepo, }, ""); err != nil { return err } @@ -248,7 +248,7 @@ func (impl *defaultToolImplementation) GetPolicyStatus( host := r.Hostname if host == "" { - host = "github.com" + host = githubHostname } prNr, err := impl.SearchPullRequest(ctx, a, &models.Repository{ Hostname: host, diff --git a/pkg/sourcetool/models/models.go b/pkg/sourcetool/models/models.go index 06b9246..7e9422c 100644 --- a/pkg/sourcetool/models/models.go +++ b/pkg/sourcetool/models/models.go @@ -69,6 +69,12 @@ const ( CONFIG_TAG_RULES ControlConfiguration = "CONFIG_TAG_RULES" ) +// Digest algorithm names used in attestation subjects +const ( + DigestTypeGitCommit = "gitCommit" + DigestTypeSha1 = "sha1" +) + type Commit struct { SHA string Author string @@ -101,7 +107,7 @@ func (c *Commit) GetCommit() *Commit { func (c *Commit) ToResourceDescriptor() *attestation.ResourceDescriptor { return &attestation.ResourceDescriptor{ Digest: map[string]string{ - "sha1": c.SHA, "gitCommit": c.SHA, + DigestTypeSha1: c.SHA, DigestTypeGitCommit: c.SHA, }, } } diff --git a/pkg/sourcetool/tool.go b/pkg/sourcetool/tool.go index e3a7aee..aace6e7 100644 --- a/pkg/sourcetool/tool.go +++ b/pkg/sourcetool/tool.go @@ -36,6 +36,9 @@ var ControlConfigurations = []models.ControlConfiguration{ models.CONFIG_POLICY, models.CONFIG_GEN_PROVENANCE, models.CONFIG_BRANCH_RULES, models.CONFIG_TAG_RULES, } +// githubHostname is the hostname of the VCS system sourcetool supports (for now) +const githubHostname = "github.com" + // New initializes a new source tool instance. func New(funcs ...ConfigFn) (*Tool, error) { t := &Tool{ @@ -194,7 +197,7 @@ func (t *Tool) FindPolicyPR(ctx context.Context, repo *models.Repository) (*mode } pr, err := t.impl.SearchPullRequest(ctx, t.Authenticator, &models.Repository{ - Hostname: "github.com", + Hostname: githubHostname, Path: fmt.Sprintf("%s/%s", policyRepoOwner, policyRepoRepo), }, fmt.Sprintf("Add %s SLSA Source policy file", repo.Path)) if err != nil {