Skip to content

Commit

Permalink
Add more endpoints @coderabbitai (#158)
Browse files Browse the repository at this point in the history
* Add more endpoints

- Added AddNode and SetDependency to the Graph service

Signed-off-by: neilnaveen <[email protected]>

* Tweaked the code better

Signed-off-by: naveensrinivasan <[email protected]>

---------

Signed-off-by: neilnaveen <[email protected]>
Signed-off-by: naveensrinivasan <[email protected]>
Co-authored-by: naveensrinivasan <[email protected]>
  • Loading branch information
neilnaveen and naveensrinivasan authored Nov 27, 2024
1 parent 9dd19fa commit fbc0864
Show file tree
Hide file tree
Showing 9 changed files with 547 additions and 153 deletions.
74 changes: 51 additions & 23 deletions api/v1/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,67 +48,95 @@ type Query struct {
func (s *Service) GetNode(ctx context.Context, req *connect.Request[service.GetNodeRequest]) (*connect.Response[service.GetNodeResponse], error) {
node, err := s.storage.GetNode(req.Msg.Id)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get node by id: %w", err)
}
serviceNode, err := NodeToServiceNode(node)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to convert node to service node: %w", err)
}
return connect.NewResponse(&service.GetNodeResponse{Node: serviceNode}), nil
}

func (s *Service) GetNodeByName(ctx context.Context, req *connect.Request[service.GetNodeByNameRequest]) (*connect.Response[service.GetNodeByNameResponse], error) {
id, err := s.storage.NameToID(req.Msg.Name)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get node by name: %w", err)
}
node, err := s.storage.GetNode(id)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get node by id: %w", err)
}
serviceNode, err := NodeToServiceNode(node)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to convert node to service node: %w", err)
}
return connect.NewResponse(&service.GetNodeByNameResponse{Node: serviceNode}), nil
}

func (s *Service) GetNodesByGlob(ctx context.Context, req *connect.Request[service.GetNodesByGlobRequest]) (*connect.Response[service.GetNodesByGlobResponse], error) {
nodes, err := s.storage.GetNodesByGlob(req.Msg.Pattern)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get nodes by glob: %w", err)
}
serviceNodes := make([]*service.Node, 0, len(nodes))
for _, node := range nodes {
serviceNode, err := NodeToServiceNode(node)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to convert node to service node: %w", err)
}
serviceNodes = append(serviceNodes, serviceNode)
}
return connect.NewResponse(&service.GetNodesByGlobResponse{Nodes: serviceNodes}), nil
}

func (s *Service) AddNode(ctx context.Context, req *connect.Request[service.AddNodeRequest]) (*connect.Response[service.AddNodeResponse], error) {
resultNode, err := graph.AddNode(s.storage, req.Msg.Node.Type, req.Msg.Node.Metadata, req.Msg.Node.Name)
if err != nil {
return nil, fmt.Errorf("failed to add node: %w", err)
}
serviceNode, err := NodeToServiceNode(resultNode)
if err != nil {
return nil, fmt.Errorf("failed to convert node to service node: %w", err)
}
return connect.NewResponse(&service.AddNodeResponse{Node: serviceNode}), nil
}

func (s *Service) SetDependency(ctx context.Context, req *connect.Request[service.SetDependencyRequest]) (*connect.Response[emptypb.Empty], error) {
fromNode, err := s.storage.GetNode(req.Msg.NodeId)
if err != nil {
return nil, err
}
toNode, err := s.storage.GetNode(req.Msg.DependencyID)
if err != nil {
return nil, err
}
err = fromNode.SetDependency(s.storage, toNode)
if err != nil {
return nil, err
}
return connect.NewResponse(&emptypb.Empty{}), nil
}

func (s *Service) Cache(ctx context.Context, req *connect.Request[emptypb.Empty]) (*connect.Response[emptypb.Empty], error) {
err := graph.Cache(s.storage)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to cache: %w", err)
}
return connect.NewResponse(&emptypb.Empty{}), nil
}

func (s *Service) Clear(ctx context.Context, req *connect.Request[emptypb.Empty]) (*connect.Response[emptypb.Empty], error) {
err := s.storage.RemoveAllCaches()
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to clear: %w", err)
}
return connect.NewResponse(&emptypb.Empty{}), nil
}

func (s *Service) CustomLeaderboard(ctx context.Context, req *connect.Request[service.CustomLeaderboardRequest]) (*connect.Response[service.CustomLeaderboardResponse], error) {
uncachedNodes, err := s.storage.ToBeCached()
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get uncached nodes: %w", err)
}
if len(uncachedNodes) != 0 {
return nil, fmt.Errorf("cannot use sorted leaderboards without caching")
Expand Down Expand Up @@ -211,18 +239,18 @@ func (s *Service) CustomLeaderboard(ctx context.Context, req *connect.Request[se
func (s *Service) AllKeys(ctx context.Context, req *connect.Request[emptypb.Empty]) (*connect.Response[service.AllKeysResponse], error) {
keys, err := s.storage.GetAllKeys()
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get all keys: %w", err)
}
nodes, err := s.storage.GetNodes(keys)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get nodes by keys: %w", err)
}

resultNodes := make([]*service.Node, 0, len(nodes))
for _, node := range nodes {
query, err := NodeToServiceNode(node)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to convert node to service node: %w", err)
}
resultNodes = append(resultNodes, query)
}
Expand All @@ -238,37 +266,37 @@ func (s *Service) Query(ctx context.Context, req *connect.Request[service.QueryR
}
keys, err := s.storage.GetAllKeys()
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get all keys: %w", err)
}

nodes, err := s.storage.GetNodes(keys)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get nodes by keys: %w", err)
}

caches, err := s.storage.GetCaches(keys)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get caches by keys: %w", err)
}
cacheStack, err := s.storage.ToBeCached()
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get to be cached nodes: %w", err)
}
result, err := graph.ParseAndExecute(req.Msg.Script, s.storage, "", nodes, caches, len(cacheStack) == 0)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to parse and execute script: %w", err)
}

outputNodes, err := s.storage.GetNodes(result.ToArray())
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get nodes by ids: %w", err)
}

resultNodes := make([]*service.Node, 0, len(outputNodes))
for _, node := range outputNodes {
query, err := NodeToServiceNode(node)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to convert node to service node: %w", err)
}
resultNodes = append(resultNodes, query)
}
Expand All @@ -287,23 +315,23 @@ func (s *Service) Check(ctx context.Context, req *connect.Request[emptypb.Empty]
func (s *Service) IngestSBOM(ctx context.Context, req *connect.Request[service.IngestSBOMRequest]) (*connect.Response[emptypb.Empty], error) {
err := ingest.SBOM(s.storage, req.Msg.Sbom)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to ingest sbom: %w", err)
}
return connect.NewResponse(&emptypb.Empty{}), nil
}

func (s *Service) IngestVulnerability(ctx context.Context, req *connect.Request[service.IngestVulnerabilityRequest]) (*connect.Response[emptypb.Empty], error) {
err := ingest.Vulnerabilities(s.storage, req.Msg.Vulnerability)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to ingest vulnerability: %w", err)
}
return connect.NewResponse(&emptypb.Empty{}), nil
}

func (s *Service) IngestScorecard(ctx context.Context, req *connect.Request[service.IngestScorecardRequest]) (*connect.Response[emptypb.Empty], error) {
err := ingest.Scorecards(s.storage, req.Msg.Scorecard)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to ingest scorecard: %w", err)
}
return connect.NewResponse(&emptypb.Empty{}), nil
}
Expand Down
15 changes: 15 additions & 0 deletions api/v1/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ message GetNodesByGlobResponse {
repeated Node nodes = 1;
}

message AddNodeRequest {
Node node = 1;
}

message AddNodeResponse {
Node node = 1;
}

message SetDependencyRequest {
uint32 nodeId = 1;
uint32 dependencyID = 2;
}

message IngestSBOMRequest {
bytes sbom = 1;
}
Expand Down Expand Up @@ -98,6 +111,8 @@ service GraphService {
rpc GetNode(GetNodeRequest) returns (GetNodeResponse) {}
rpc GetNodesByGlob(GetNodesByGlobRequest) returns (GetNodesByGlobResponse) {}
rpc GetNodeByName(GetNodeByNameRequest) returns (GetNodeByNameResponse) {}
rpc AddNode(AddNodeRequest) returns (AddNodeResponse) {}
rpc SetDependency(SetDependencyRequest) returns (google.protobuf.Empty) {}
}

service IngestService {
Expand Down
53 changes: 53 additions & 0 deletions api/v1/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,59 @@ func TestIngestScorecard(t *testing.T) {
require.NoError(t, err)
}

func TestAddNode(t *testing.T) {
s := setupService()
addNodeReq := connect.NewRequest(&service.AddNodeRequest{
Node: &service.Node{Name: "test_node", Type: "type1"},
})
_, err := s.AddNode(context.Background(), addNodeReq)
require.NoError(t, err)
getNodeReq := connect.NewRequest(&service.GetNodeByNameRequest{Name: "test_node"})
resp, err := s.GetNodeByName(context.Background(), getNodeReq)
require.NoError(t, err)
assert.NotNil(t, resp.Msg.Node)
assert.Equal(t, "test_node", resp.Msg.Node.Name)

getNodeReq = connect.NewRequest(&service.GetNodeByNameRequest{Name: "nonexistent_node"})
resp, err = s.GetNodeByName(context.Background(), getNodeReq)
require.Error(t, err)
assert.Nil(t, resp)
}

func TestSetDependency(t *testing.T) {
s := setupService()
addNodeReq := connect.NewRequest(&service.AddNodeRequest{
Node: &service.Node{Name: "test_node", Type: "type1"},
})
node1, err := s.AddNode(context.Background(), addNodeReq)
require.NoError(t, err)
addNodeReq2 := connect.NewRequest(&service.AddNodeRequest{
Node: &service.Node{Name: "test_node2", Type: "type1"},
})
node2, err := s.AddNode(context.Background(), addNodeReq2)
require.NoError(t, err)
setDependencyReq := connect.NewRequest(&service.SetDependencyRequest{
NodeId: node1.Msg.Node.Id,
DependencyID: node2.Msg.Node.Id,
})
_, err = s.SetDependency(context.Background(), setDependencyReq)
require.NoError(t, err)
getNodeReq := connect.NewRequest(&service.GetNodeByNameRequest{Name: "test_node"})
resp, err := s.GetNodeByName(context.Background(), getNodeReq)
require.NoError(t, err)
assert.NotNil(t, resp.Msg.Node)
assert.NotEmpty(t, resp.Msg.Node.Dependencies, "Dependencies slice should not be empty")
assert.Equal(t, resp.Msg.Node.Dependencies[0], node2.Msg.Node.Id)
t.Run("non-existent node", func(t *testing.T) {
invalidReq := connect.NewRequest(&service.SetDependencyRequest{
NodeId: 0,
DependencyID: node2.Msg.Node.Id,
})
_, err = s.SetDependency(context.Background(), invalidReq)
assert.Error(t, err)
})
}

func TestHealthCheck(t *testing.T) {
s := setupService()
req := connect.NewRequest(&emptypb.Empty{})
Expand Down
11 changes: 11 additions & 0 deletions cmd/query/getMetadata/getMetadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
apiv1 "github.com/bitbomdev/minefield/gen/api/v1"
"github.com/spf13/cobra"
"github.com/zeebo/assert"
"google.golang.org/protobuf/types/known/emptypb"
)

func TestFormatTable(t *testing.T) {
Expand Down Expand Up @@ -48,6 +49,8 @@ type mockGraphServiceClient struct {
GetNodesByGlobFunc func(ctx context.Context, req *connect.Request[apiv1.GetNodesByGlobRequest]) (*connect.Response[apiv1.GetNodesByGlobResponse], error)
GetNodeFunc func(ctx context.Context, req *connect.Request[apiv1.GetNodeRequest]) (*connect.Response[apiv1.GetNodeResponse], error)
GetNodeByNameFunc func(ctx context.Context, req *connect.Request[apiv1.GetNodeByNameRequest]) (*connect.Response[apiv1.GetNodeByNameResponse], error)
AddNodeFunc func(ctx context.Context, req *connect.Request[apiv1.AddNodeRequest]) (*connect.Response[apiv1.AddNodeResponse], error)
SetDependencyFunc func(ctx context.Context, req *connect.Request[apiv1.SetDependencyRequest]) (*connect.Response[emptypb.Empty], error)
}

func (m *mockGraphServiceClient) GetNodesByGlob(ctx context.Context, req *connect.Request[apiv1.GetNodesByGlobRequest]) (*connect.Response[apiv1.GetNodesByGlobResponse], error) {
Expand All @@ -62,6 +65,14 @@ func (m *mockGraphServiceClient) GetNodeByName(ctx context.Context, req *connect
return m.GetNodeByNameFunc(ctx, req)
}

func (m *mockGraphServiceClient) AddNode(ctx context.Context, req *connect.Request[apiv1.AddNodeRequest]) (*connect.Response[apiv1.AddNodeResponse], error) {
return m.AddNodeFunc(ctx, req)
}

func (m *mockGraphServiceClient) SetDependency(ctx context.Context, req *connect.Request[apiv1.SetDependencyRequest]) (*connect.Response[emptypb.Empty], error) {
return m.SetDependencyFunc(ctx, req)
}

func TestRun(t *testing.T) {
tests := []struct {
name string
Expand Down
10 changes: 10 additions & 0 deletions cmd/query/globsearch/globsearch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
apiv1 "github.com/bitbomdev/minefield/gen/api/v1"
"github.com/spf13/cobra"
"github.com/zeebo/assert"
"google.golang.org/protobuf/types/known/emptypb"
)

func TestFormatTable(t *testing.T) {
Expand Down Expand Up @@ -163,6 +164,8 @@ type mockGraphServiceClient struct {
GetNodesByGlobFunc func(ctx context.Context, req *connect.Request[apiv1.GetNodesByGlobRequest]) (*connect.Response[apiv1.GetNodesByGlobResponse], error)
GetNodeFunc func(ctx context.Context, req *connect.Request[apiv1.GetNodeRequest]) (*connect.Response[apiv1.GetNodeResponse], error)
GetNodeByNameFunc func(ctx context.Context, req *connect.Request[apiv1.GetNodeByNameRequest]) (*connect.Response[apiv1.GetNodeByNameResponse], error)
SetDependencyFunc func(ctx context.Context, req *connect.Request[apiv1.SetDependencyRequest]) (*connect.Response[emptypb.Empty], error)
AddNodeFunc func(ctx context.Context, req *connect.Request[apiv1.AddNodeRequest]) (*connect.Response[apiv1.AddNodeResponse], error)
}

func (m *mockGraphServiceClient) GetNodesByGlob(ctx context.Context, req *connect.Request[apiv1.GetNodesByGlobRequest]) (*connect.Response[apiv1.GetNodesByGlobResponse], error) {
Expand All @@ -177,6 +180,13 @@ func (m *mockGraphServiceClient) GetNodeByName(ctx context.Context, req *connect
return m.GetNodeByNameFunc(ctx, req)
}

func (m *mockGraphServiceClient) AddNode(ctx context.Context, req *connect.Request[apiv1.AddNodeRequest]) (*connect.Response[apiv1.AddNodeResponse], error) {
return m.AddNodeFunc(ctx, req)
}

func (m *mockGraphServiceClient) SetDependency(ctx context.Context, req *connect.Request[apiv1.SetDependencyRequest]) (*connect.Response[emptypb.Empty], error) {
return m.SetDependencyFunc(ctx, req)
}
func TestRun(t *testing.T) {
tests := []struct {
name string
Expand Down
Loading

0 comments on commit fbc0864

Please sign in to comment.