Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions data/payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"fmt"

"github.com/google/go-github/v71/github"
"github.com/google/go-github/v74/github"
"github.com/privateerproj/privateer-sdk/config"
"github.com/shurcooL/githubv4"
"golang.org/x/oauth2"
Expand All @@ -18,8 +18,8 @@ type Payload struct {
RepositoryMetadata RepositoryMetadata
DependencyManifestsCount int
IsCodeRepo bool

client *githubv4.Client
SecurityPosture SecurityPosture
client *githubv4.Client
}

func Loader(config *config.Config) (payload any, err error) {
Expand All @@ -32,7 +32,7 @@ func Loader(config *config.Config) (payload any, err error) {
&oauth2.Token{AccessToken: config.GetString("token")},
)))

repositoryMetadata, err := loadRepositoryMetadata(ghClient, config.GetString("owner"), config.GetString("repo"))
repo, repositoryMetadata, err := loadRepositoryMetadata(ghClient, config.GetString("owner"), config.GetString("repo"))
if err != nil {
return nil, err
}
Expand All @@ -52,6 +52,11 @@ func Loader(config *config.Config) (payload any, err error) {
return nil, err
}

securityPosture, err := buildSecurityPosture(repo, *rest)
if err != nil {
return nil, err
}

return any(Payload{
GraphqlRepoData: graphql,
RestData: rest,
Expand All @@ -60,6 +65,7 @@ func Loader(config *config.Config) (payload any, err error) {
DependencyManifestsCount: dependencyManifestsCount,
IsCodeRepo: isCodeRepo,
client: client,
SecurityPosture: securityPosture,
}), nil
}

Expand Down
10 changes: 5 additions & 5 deletions data/repository_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package data
import (
"context"

"github.com/google/go-github/v71/github"
"github.com/google/go-github/v74/github"
)

type RepositoryMetadata interface {
Expand Down Expand Up @@ -42,18 +42,18 @@ func (r *GitHubRepositoryMetadata) IsMFARequiredForAdministrativeActions() *bool
return r.ghOrg.TwoFactorRequirementEnabled
}

func loadRepositoryMetadata(ghClient *github.Client, owner, repo string) (data RepositoryMetadata, err error) {
func loadRepositoryMetadata(ghClient *github.Client, owner, repo string) (ghRepo *github.Repository, data RepositoryMetadata, err error) {
repository, _, err := ghClient.Repositories.Get(context.Background(), owner, repo)
if err != nil {
return &GitHubRepositoryMetadata{}, err
return repository, &GitHubRepositoryMetadata{}, err
}
organization, _, err := ghClient.Organizations.Get(context.Background(), owner)
if err != nil {
return &GitHubRepositoryMetadata{
return repository, &GitHubRepositoryMetadata{
ghRepo: repository,
}, nil
}
return &GitHubRepositoryMetadata{
return repository, &GitHubRepositoryMetadata{
ghRepo: repository,
ghOrg: organization,
}, nil
Expand Down
4 changes: 2 additions & 2 deletions data/repository_metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package data
import (
"testing"

"github.com/google/go-github/v71/github"
"github.com/google/go-github/v74/github"
"github.com/migueleliasweb/go-github-mock/src/mock"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -81,7 +81,7 @@ func TestLoadRepositoryMetadata(t *testing.T) {
testCase.responses...,
)
ghClient := github.NewClient(mockClient)
repoMetadata, err := loadRepositoryMetadata(ghClient, testCase.owner, testCase.repo)
_, repoMetadata, err := loadRepositoryMetadata(ghClient, testCase.owner, testCase.repo)
if testCase.expectedRepoError {
assert.Error(t, err)
} else {
Expand Down
12 changes: 6 additions & 6 deletions data/rest-data.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/ast"
"github.com/google/go-github/v71/github"
"github.com/google/go-github/v74/github"
"github.com/ossf/si-tooling/v2/si"
"github.com/privateerproj/privateer-sdk/config"
)
Expand Down Expand Up @@ -347,9 +347,9 @@ func (r *RestData) GetRulesets(branchName string) []Ruleset {
// to distinguish between programming, markup, data, and prose content types for more nuanced
// repository classification.
func (r *RestData) IsCodeRepo() (bool, error) {
languages, _, err := r.ghClient.Repositories.ListLanguages(context.Background(), r.owner, r.repo)
if err != nil {
return false, err
}
return len(languages) > 0, nil
languages, _, err := r.ghClient.Repositories.ListLanguages(context.Background(), r.owner, r.repo)
if err != nil {
return false, err
}
return len(languages) > 0, nil
}
2 changes: 1 addition & 1 deletion data/rest-data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"net/http"
"testing"

"github.com/google/go-github/v71/github"
"github.com/google/go-github/v74/github"
"github.com/migueleliasweb/go-github-mock/src/mock"
"github.com/stretchr/testify/assert"
)
Expand Down
62 changes: 62 additions & 0 deletions data/security-posture.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package data

import (
"github.com/google/go-github/v74/github"
"github.com/ossf/si-tooling/v2/si"
)

// SecurityPosture defines an interface for accessing security-related metadata about a repository.
type SecurityPosture interface {
PreventsPushingSecrets() bool
ScansForSecrets() bool
DefinesPolicyForHandlingSecrets() bool
}

type RepoSecurityPosture struct {
restData RestData
preventsSecretPushing bool
scansForSecrets bool
definesPolicyForHandlingSecrets bool
}

func buildSecurityPosture(repository *github.Repository, rd RestData) (SecurityPosture, error) {
securityConfig := repository.GetSecurityAndAnalysis()
if securityConfig == nil {
return &RepoSecurityPosture{
restData: rd,
}, nil
}
secretsScanningStatus := securityConfig.GetSecretScanning().GetStatus()
insightsClaimsSecretsTooling := insightsClaimsSecretsTooling(rd.Insights)
return &RepoSecurityPosture{
restData: rd,
preventsSecretPushing: secretsScanningStatus == "enabled" || insightsClaimsSecretsTooling,
scansForSecrets: secretsScanningStatus == "enabled" || insightsClaimsSecretsTooling,
// TODO: consider if SecurityInsights should have a policy doc field in ProjectDocumentation to handle this
// definesPolicyForHandlingSecrets: rd.SecurityInsights != nil && ....
}, nil
}

func insightsClaimsSecretsTooling(insights si.SecurityInsights) bool {
if insights.Repository.Security.Tools == nil {
return false
}
for _, tool := range insights.Repository.Security.Tools {
if tool.Type == "secret-scanning" {
return true
}
}
return false
}

func (rsp *RepoSecurityPosture) PreventsPushingSecrets() bool {
return rsp.preventsSecretPushing
}

func (rsp *RepoSecurityPosture) ScansForSecrets() bool {
return rsp.scansForSecrets
}

func (rsp *RepoSecurityPosture) DefinesPolicyForHandlingSecrets() bool {
return rsp.definesPolicyForHandlingSecrets
}
94 changes: 94 additions & 0 deletions data/security-posture_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package data

import (
"testing"

"github.com/google/go-github/v74/github"
"github.com/ossf/si-tooling/v2/si"
"github.com/stretchr/testify/assert"
)

func TestRepoSecurityPostureMethods(t *testing.T) {
rsp := &RepoSecurityPosture{
preventsSecretPushing: true,
scansForSecrets: true,
definesPolicyForHandlingSecrets: false,
}

assert.True(t, rsp.PreventsPushingSecrets())
assert.True(t, rsp.ScansForSecrets())
assert.False(t, rsp.DefinesPolicyForHandlingSecrets())
}

func TestBuildSecurityPosture_NoSecurityConfig(t *testing.T) {
repo := &github.Repository{}
rd := RestData{}
sp, err := buildSecurityPosture(repo, rd)
assert.NoError(t, err)
assert.NotNil(t, sp)
assert.False(t, sp.PreventsPushingSecrets())
assert.False(t, sp.ScansForSecrets())
assert.False(t, sp.DefinesPolicyForHandlingSecrets())
}

func TestBuildSecurityPosture_SecretScanningEnabled(t *testing.T) {
repo := &github.Repository{
SecurityAndAnalysis: &github.SecurityAndAnalysis{
SecretScanning: &github.SecretScanning{
Status: github.Ptr("enabled"),
},
},
}
rd := RestData{}
sp, err := buildSecurityPosture(repo, rd)
assert.NoError(t, err)
assert.True(t, sp.PreventsPushingSecrets())
assert.True(t, sp.ScansForSecrets())
}

func TestBuildSecurityPosture_SecretScanningDisabledButInsightsTooling(t *testing.T) {
repo := &github.Repository{
SecurityAndAnalysis: &github.SecurityAndAnalysis{
SecretScanning: &github.SecretScanning{
Status: github.Ptr("disabled"),
},
},
}
rd := RestData{
Insights: si.SecurityInsights{
Repository: si.Repository{
Security: si.SecurityInfo{
Tools: []si.Tool{
{Type: "secret-scanning"},
},
},
},
},
}
sp, err := buildSecurityPosture(repo, rd)
assert.NoError(t, err)
assert.True(t, sp.PreventsPushingSecrets())
assert.True(t, sp.ScansForSecrets())
}

func TestInsightsClaimsSecretsTooling(t *testing.T) {
insights := si.SecurityInsights{
Repository: si.Repository{
Security: si.SecurityInfo{
Tools: []si.Tool{
{Type: "secret-scanning"},
{Type: "other-tool"},
},
},
},
}
assert.True(t, insightsClaimsSecretsTooling(insights))

insights.Repository.Security.Tools = []si.Tool{
{Type: "other-tool"},
}
assert.False(t, insightsClaimsSecretsTooling(insights))

insights.Repository.Security.Tools = nil
assert.False(t, insightsClaimsSecretsTooling(insights))
}
30 changes: 30 additions & 0 deletions evaluation_plans/osps/build_release/evaluations.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,33 @@ func OSPS_BR_06() (evaluation *layer4.ControlEvaluation) {

return
}

func OSPS_BR_07() (evaluation *layer4.ControlEvaluation) {
evaluation = &layer4.ControlEvaluation{
ControlID: "OSPS-BR-07",
}

evaluation.AddAssessment(
"OSPS-BR-07.01",
"The project MUST prevent the unintentional storage of unencrypted sensitive data, such as secrets and credentials, in the version control system.",
[]string{
"Maturity Level 1",
},
[]layer4.AssessmentStep{
secretScanningInUse,
},
)

evaluation.AddAssessment(
"OSPS-BR-07.02",
"The project MUST define a policy for managing secrets and credentials used by the project. The policy should include guidelines for storing, accessing, and rotating secrets and credentials.",
[]string{
"Maturity Level 3",
},
[]layer4.AssessmentStep{
reusable_steps.NotImplemented,
},
)

return
}
15 changes: 15 additions & 0 deletions evaluation_plans/osps/build_release/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,18 @@ func distributionPointsUseHTTPS(payloadData any, _ map[string]*layer4.Change) (r
}
return layer4.Passed, "All distribution points use HTTPS"
}

func secretScanningInUse(payloadData any, _ map[string]*layer4.Change) (result layer4.Result, message string) {
data, message := reusable_steps.VerifyPayload(payloadData)
if message != "" {
return layer4.Unknown, message
}

if data.SecurityPosture.PreventsPushingSecrets() && data.SecurityPosture.ScansForSecrets() {
return layer4.Passed, "Secret scanning is enabled and prevents pushing secrets"
} else if data.SecurityPosture.PreventsPushingSecrets() || data.SecurityPosture.ScansForSecrets() {
return layer4.Failed, "Secret scanning is only partially enabled"
} else {
return layer4.Failed, "Secret scanning is not enabled"
}
}
Comment thread
trumant marked this conversation as resolved.
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.24.4

require (
github.com/goccy/go-yaml v1.18.0
github.com/google/go-github/v71 v71.0.0
github.com/google/go-github/v74 v74.0.0
github.com/migueleliasweb/go-github-mock v1.4.0
github.com/ossf/gemara v0.7.1
github.com/ossf/si-tooling/v2 v2.0.5-0.20250508212737-7ddcc8c43db9
Expand All @@ -18,6 +18,7 @@ require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/defenseunicorns/go-oscal v0.6.3 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/google/go-github/v71 v71.0.0 // indirect
github.com/google/go-github/v73 v73.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ github.com/google/go-github/v71 v71.0.0 h1:Zi16OymGKZZMm8ZliffVVJ/Q9YZreDKONCr+W
github.com/google/go-github/v71 v71.0.0/go.mod h1:URZXObp2BLlMjwu0O8g4y6VBneUj2bCHgnI8FfgZ51M=
github.com/google/go-github/v73 v73.0.0 h1:aR+Utnh+Y4mMkS+2qLQwcQ/cF9mOTpdwnzlaw//rG24=
github.com/google/go-github/v73 v73.0.0/go.mod h1:fa6w8+/V+edSU0muqdhCVY7Beh1M8F1IlQPZIANKIYw=
github.com/google/go-github/v74 v74.0.0 h1:yZcddTUn8DPbj11GxnMrNiAnXH14gNs559AsUpNpPgM=
github.com/google/go-github/v74 v74.0.0/go.mod h1:ubn/YdyftV80VPSI26nSJvaEsTOnsjrxG3o9kJhcyak=
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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
Expand Down
Loading