Skip to content

Commit 06c7c7c

Browse files
Merge pull request #4 from compliance-framework/feat/support-security-team-name
BCH 1033: Add support for defining security team name
2 parents b06249c + c6faabf commit 06c7c7c

3 files changed

Lines changed: 97 additions & 13 deletions

File tree

Makefile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# The help target prints out all targets with their descriptions organized
2+
# beneath their categories. The categories are represented by '##@' and the
3+
# target descriptions by '##'. The awk commands is responsible for reading the
4+
# entire set of makefiles included in this invocation, looking for lines of the
5+
# file as xyz: ## something, and then pretty-format the target and help. Then,
6+
# if there's a line with ##@ something, that gets pretty-printed as a category.
7+
# More info on the usage of ANSI catalog characters for terminal formatting:
8+
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
9+
# More info on the awk command:
10+
# http://linuxcommand.org/lc3_adv_awk.php
11+
12+
# Check if OPA CLI is installed
13+
OPA := $(shell command -v opa 2> /dev/null)
14+
ifeq ($(OPA),)
15+
$(error "opa CLI not found. Please install it: https://www.openpolicyagent.org/docs/latest/cli/")
16+
endif
17+
18+
##@ Help
19+
help: ## Display this concise help, ie only the porcelain target
20+
@awk 'BEGIN {FS = ":.*##"; printf "\033[1mUsage\033[0m\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-30s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
21+
22+
help-all: ## Display all help items, ie including plumbing targets
23+
@awk 'BEGIN {FS = ":.*#"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?#/ { printf " \033[36m%-25s\033[0m %s\n", $$1, $$2 } /^#@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
24+
25+
# Bundle the policies into a tarball for OCI registry
26+
clean: # Cleanup build artifacts
27+
@rm -rf dist/*
28+
29+
build: clean ## Build the policy bundle
30+
@mkdir -p dist/
31+
@go build -o dist/plugin main.go

main.go

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,37 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"slices"
8+
79
policyManager "github.com/compliance-framework/agent/policy-manager"
810
"github.com/compliance-framework/agent/runner"
911
"github.com/compliance-framework/agent/runner/proto"
1012
"github.com/google/go-github/v71/github"
1113
"github.com/hashicorp/go-hclog"
1214
goplugin "github.com/hashicorp/go-plugin"
1315
"github.com/mitchellh/mapstructure"
14-
"slices"
1516
)
1617

1718
type PluginConfig struct {
18-
Token string `mapstructure:"token"`
19-
Organization *string `mapstructure:"organization"`
20-
User *string `mapstructure:"user"`
19+
Token string `mapstructure:"token"`
20+
Organization *string `mapstructure:"organization"`
21+
User *string `mapstructure:"user"`
22+
SecurityTeamName *string `mapstructure:"security-team-name"`
2123
}
2224

2325
type DependabotPlugin struct {
2426
logger hclog.Logger
25-
data map[string]interface{}
26-
config *PluginConfig
2727

28+
config *PluginConfig
2829
githubClient *github.Client
2930
}
3031

32+
type DependabotData struct {
33+
Alerts []*github.DependabotAlert
34+
SecurityTeamMembers []*github.User
35+
}
36+
3137
func (l *DependabotPlugin) Configure(req *proto.ConfigureRequest) (*proto.ConfigureResponse, error) {
32-
//l.config = req.GetConfig()
3338
config := &PluginConfig{}
3439
mapstructure.Decode(req.GetConfig(), config)
3540
l.config = config
@@ -42,7 +47,20 @@ func (l *DependabotPlugin) Configure(req *proto.ConfigureRequest) (*proto.Config
4247
func (l *DependabotPlugin) Eval(req *proto.EvalRequest, apiHelper runner.ApiHelper) (*proto.EvalResponse, error) {
4348
ctx := context.TODO()
4449
repochan, errchan := l.FetchRepositories(ctx)
50+
51+
var securityTeamMembers []*github.User
52+
if l.config.SecurityTeamName != nil && *l.config.SecurityTeamName != "" {
53+
var err error
54+
securityTeamMembers, err = l.FetchSecurityTeamMembers(ctx)
55+
if err != nil {
56+
return &proto.EvalResponse{
57+
Status: proto.ExecutionStatus_FAILURE,
58+
}, err
59+
}
60+
}
61+
4562
done := false
63+
4664
for !done {
4765
select {
4866
case err, ok := <-errchan:
@@ -66,7 +84,14 @@ func (l *DependabotPlugin) Eval(req *proto.EvalRequest, apiHelper runner.ApiHelp
6684
}, err
6785
}
6886

69-
evidences, err := l.EvaluatePolicies(ctx, repo, alerts, req)
87+
data := &DependabotData{
88+
Alerts: alerts,
89+
}
90+
if securityTeamMembers != nil {
91+
data.SecurityTeamMembers = securityTeamMembers
92+
}
93+
94+
evidences, err := l.EvaluatePolicies(ctx, repo, data, req)
7095
if err != nil {
7196
return &proto.EvalResponse{
7297
Status: proto.ExecutionStatus_FAILURE,
@@ -87,6 +112,14 @@ func (l *DependabotPlugin) Eval(req *proto.EvalRequest, apiHelper runner.ApiHelp
87112
}, nil
88113
}
89114

115+
func (l *DependabotPlugin) FetchSecurityTeamMembers(ctx context.Context) ([]*github.User, error) {
116+
members, _, err := l.githubClient.Teams.ListTeamMembersBySlug(ctx, *l.config.Organization, *l.config.SecurityTeamName, nil)
117+
if err != nil {
118+
return nil, err
119+
}
120+
return members, nil
121+
}
122+
90123
func (l *DependabotPlugin) FetchRepositoryDependabotAlerts(ctx context.Context, repo *github.Repository) ([]*github.DependabotAlert, error) {
91124
alerts, _, err := l.githubClient.Dependabot.ListRepoAlerts(ctx, repo.GetOwner().GetLogin(), repo.GetName(), &github.ListAlertsOptions{
92125
ListOptions: github.ListOptions{
@@ -140,7 +173,7 @@ func (l *DependabotPlugin) FetchRepositories(ctx context.Context) (<-chan *githu
140173
return repositories, errs
141174
}
142175

143-
func (l *DependabotPlugin) EvaluatePolicies(ctx context.Context, repo *github.Repository, alerts []*github.DependabotAlert, req *proto.EvalRequest) ([]*proto.Evidence, error) {
176+
func (l *DependabotPlugin) EvaluatePolicies(ctx context.Context, repo *github.Repository, data *DependabotData, req *proto.EvalRequest) ([]*proto.Evidence, error) {
144177
var accumulatedErrors error
145178

146179
activities := make([]*proto.Activity, 0)
@@ -260,7 +293,7 @@ func (l *DependabotPlugin) EvaluatePolicies(ctx context.Context, repo *github.Re
260293
actors,
261294
activities,
262295
)
263-
evidence, err := processor.GenerateResults(ctx, policyPath, alerts)
296+
evidence, err := processor.GenerateResults(ctx, policyPath, data)
264297
evidences = slices.Concat(evidences, evidence)
265298
if err != nil {
266299
accumulatedErrors = errors.Join(accumulatedErrors, err)

main_integration_test.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ package main
44

55
import (
66
"context"
7+
"os"
8+
"testing"
9+
710
policy_manager "github.com/compliance-framework/agent/policy-manager"
811
"github.com/google/go-github/v71/github"
912
"github.com/hashicorp/go-hclog"
10-
"os"
11-
"testing"
1213
)
1314

1415
func TestDependabotPlugin_Integration_FetchRepositories(t *testing.T) {
15-
1616
ctx := context.Background()
1717

1818
plugin := DependabotPlugin{
@@ -76,3 +76,23 @@ func TestDependabotPlugin_Integration_FetchRepositoryDependabotAlerts(t *testing
7676

7777
t.Log("Successfully collected alerts", len(alerts))
7878
}
79+
80+
func TestDependabotPlugin_Integration_FetchTeamMembers(t *testing.T) {
81+
ctx := context.Background()
82+
83+
plugin := DependabotPlugin{
84+
logger: hclog.NewNullLogger(),
85+
config: &PluginConfig{
86+
Token: os.Getenv("GITHUB_TOKEN"),
87+
Organization: policy_manager.Pointer("compliance-framework"),
88+
SecurityTeamName: policy_manager.Pointer("security"),
89+
},
90+
githubClient: github.NewClient(nil).WithAuthToken(os.Getenv("GITHUB_TOKEN")),
91+
}
92+
93+
members, err := plugin.FetchSecurityTeamMembers(ctx)
94+
if err != nil {
95+
t.Error(err)
96+
}
97+
t.Log("Successfully collected security team members", members)
98+
}

0 commit comments

Comments
 (0)