Skip to content

Commit

Permalink
Generate code for client-side queries for GUAC. (guacsec#522)
Browse files Browse the repository at this point in the history
* Generate code for client-side queries for GUAC.

These are the queries that GUAC parsers would create/execute to ingest
data into the backend. This ensure backend separation from the rest of
GUAC.

I added a simple example to ingest Scorecards, but in time we'll add
more.

Signed-off-by: Mihai Maruseac <[email protected]>

* Format fixes

Signed-off-by: Mihai Maruseac <[email protected]>

* Document the steps in `make fmt` to make failures easier to parse

Signed-off-by: Mihai Maruseac <[email protected]>

* Fix typo

Signed-off-by: Mihai Maruseac <[email protected]>

* Fix format again

Signed-off-by: Mihai Maruseac <[email protected]>

* Excluded from copyright

Signed-off-by: Mihai Maruseac <[email protected]>

* Separate ingestion to separate function

Signed-off-by: Mihai Maruseac <[email protected]>

* Fix code

Signed-off-by: Mihai Maruseac <[email protected]>

* Final fix

Signed-off-by: Mihai Maruseac <[email protected]>

---------

Signed-off-by: Mihai Maruseac <[email protected]>
  • Loading branch information
mihaimaruseac authored Mar 2, 2023
1 parent 2050d84 commit 7700f6b
Show file tree
Hide file tree
Showing 11 changed files with 792 additions and 10 deletions.
1 change: 1 addition & 0 deletions .github/scripts/excluded_from_copyright
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
./pkg/assembler/clients/generated/operations.go
./pkg/assembler/graphql/model/nodes.go
./pkg/assembler/graphql/resolvers/schema.resolvers.go
./pkg/assembler/graphql/generated/root_.generated.go
Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ cover: test
# Check the formatting
.PHONY: fmt
fmt:
@echo "Testing formatting and imports"
test -z "$(shell find . -name '*.go' -not -wholename './vendor/*' -not -name '*.pb.go' -exec goimports -l -e {} \;)"
@echo "Testing copyright notice"
test -z "$(shell find . -name '*.go' -not -wholename './vendor/*' -not -name '*.pb.go' -exec .github/scripts/copyright.sh {} \;)"

# Check that generated files are up to date
Expand Down
76 changes: 76 additions & 0 deletions cmd/graphql_playground/cmd/ingest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// Copyright 2023 The GUAC Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
"context"
"fmt"
"net/http"
"time"

"github.com/Khan/genqlient/graphql"
model "github.com/guacsec/guac/pkg/assembler/clients/generated"
"github.com/guacsec/guac/pkg/logging"
)

func ingestData(port int) {
ctx := logging.WithLogger(context.Background())
logger := logging.FromContext(ctx)

// ensure server is up
time.Sleep(1 * time.Second)

// Create a http client to send the mutation through
url := fmt.Sprintf("http://localhost:%d/query", port)
httpClient := http.Client{}
gqlclient := graphql.NewClient(url, &httpClient)

logger.Infof("Ingesting test data into backend server")
ingestScorecards(ctx, gqlclient)
logger.Infof("Finished ingesting test data into backend server")
}

func ingestScorecards(ctx context.Context, client graphql.Client) {
logger := logging.FromContext(ctx)

source := model.SourceInputSpec{
Type: "git",
Namespace: "github",
Name: "github.com/tensorflow/tensorflow",
Tag: "v2.12.0",
}
checks := []model.ScorecardCheckInputSpec{
{Check: "Binary_Artifacts", Score: 4},
{Check: "Branch_Protection", Score: 3},
{Check: "Code_Review", Score: 2},
{Check: "Contributors", Score: 1},
}
scorecard := model.ScorecardInputSpec{
Checks: checks,
AggregateScore: 2.9,
TimeScanned: time.Now(),
ScorecardVersion: "v4.10.2",
ScorecardCommit: "5e6a521",
Origin: "Demo ingestion",
Collector: "Demo ingestion",
}
resp, err := model.Scorecard(context.Background(), client, source, scorecard)
if err != nil {
// TODO(mihaimaruseac): Panic or just error and continue?
logger.Errorf("Error in ingesting: %v\n", err)
}
fmt.Printf("Response is |%v|\n", resp)
}
19 changes: 12 additions & 7 deletions cmd/graphql_playground/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ import (
"github.com/guacsec/guac/pkg/logging"
)

const defaultPort = "8080"

func startServer() {
ctx := logging.WithLogger(context.Background())
logger := logging.FromContext(ctx)
Expand All @@ -44,10 +42,11 @@ func startServer() {
var topResolver resolvers.Resolver
if flags.neo4jBackend {
args := neo4j.Neo4jConfig{
User: flags.gdbuser,
Pass: flags.gdbpass,
Realm: flags.realm,
DBAddr: flags.dbAddr,
User: flags.gdbuser,
Pass: flags.gdbpass,
Realm: flags.realm,
DBAddr: flags.dbAddr,
// TODO(mihaimaruseac): Once all ingestion is done, remove from here
TestData: flags.addTestData,
}

Expand All @@ -72,10 +71,16 @@ func startServer() {
config := generated.Config{Resolvers: &topResolver}
srv := handler.NewDefaultServer(generated.NewExecutableSchema(config))

// Ingest additional test data in a go-routine.
port := flags.playgroundPort
if flags.addTestData {
go ingestData(port)
}

http.Handle("/", playground.Handler("GraphQL playground", "/query"))
http.Handle("/query", srv)

port := flags.playgroundPort
logger.Infof("connect to http://localhost:%d/ for GraphQL playground", port)
// blocking until termination
logger.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
}
2 changes: 0 additions & 2 deletions pkg/assembler/backends/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ project.

**Note**: This is still in experimental state and might change in the future!

Here is a description of the contents of this subtree:

## Backend definition

- `backends.go`: defines the 2 interfaces needed to create a backend: one that
Expand Down
35 changes: 35 additions & 0 deletions pkg/assembler/clients/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
assembler/clients
=================

This directory contains the GraphQL definition for the client-side of the
["Refactoring the GUAC
Assembler"](https://docs.google.com/document/d/1yZ3-ZcfnRDWgw9uZlPuLmIHS9pNMr3DO_AEbHsDXmN8/edit?usp=sharing)
project.

**Note**: This is still in experimental state and might change in the future!

Code outside of `assembler/backends` and `assembler/graphql` should not use
structs defined in `assembler/graphql` directly as these should only be valid
server side, being regenerated when the GraphQL schema changes.

Instead, code should use the structs defined here (or in similar other clients
for utilities building on top of GUAC). These are generated based on the query
documents that we want to send to the server.

## GraphQL client configuration

- `genqlient.yaml`: the configuration file for
[`genqlient`](https://github.com/Khan/genqlient) to generate Go code from
GraphQL schema specification and the operation queries
- `operations/`: the GraphQL queries that the client (e.g., GUAC) sends to the
server (e.g., GUAC database backend, via GraphQL)

## GraphQL client code generation

- `graphql.go`: Mostly empty, contains load bearing comment to make sure Go code
is generated by `go generate ./...` whenever schema/operations change
- `generated/`: Contains code generated via `go generate ./...` to marshal a
GraphQL query from Go structures and send it to the server. When the response
is returned, the same code transforms the response into Go structures. This is
based on what is included in `operations/` and the GraphQL schema as defined
at the time of last generation.
Loading

0 comments on commit 7700f6b

Please sign in to comment.