From cfaa70ad42aff1d2382ebc67d24d533ee3b685a7 Mon Sep 17 00:00:00 2001 From: Gagan H R Date: Tue, 19 May 2026 00:01:08 +0530 Subject: [PATCH] chore: deprecate Neo4j backend implementation Signed-off-by: Gagan H R --- .golangci.yaml | 4 - Makefile | 3 - README.md | 6 - cmd/README.md | 6 +- cmd/guacgql/cmd/server.go | 2 - container_files/neo4j.yaml | 38 - container_files/neo4j/guac.yaml | 33 - go.mod | 1 - go.sum | 2 - guac.yaml | 16 +- internal/testing/cmd/pubsub_test/cmd/root.go | 11 +- pkg/assembler/backends/README.md | 1 - pkg/assembler/backends/arangodb/pkg.go | 2 - pkg/assembler/backends/neo4j/artifact.go | 145 ---- pkg/assembler/backends/neo4j/backend.go | 187 ----- pkg/assembler/backends/neo4j/builder.go | 110 --- pkg/assembler/backends/neo4j/certifyBad.go | 276 -------- pkg/assembler/backends/neo4j/certifyGood.go | 270 -------- .../backends/neo4j/certifyScorecard.go | 313 --------- .../backends/neo4j/certifyVEXStatement.go | 653 ------------------ pkg/assembler/backends/neo4j/certifyVuln.go | 567 --------------- pkg/assembler/backends/neo4j/contact.go | 39 -- pkg/assembler/backends/neo4j/hasMetadata.go | 39 -- pkg/assembler/backends/neo4j/hasSBOM.go | 200 ------ pkg/assembler/backends/neo4j/hasSLSA.go | 610 ---------------- pkg/assembler/backends/neo4j/hasSourceAt.go | 171 ----- pkg/assembler/backends/neo4j/hashEqual.go | 151 ---- .../backends/neo4j/ingest_testdata.go | 287 -------- pkg/assembler/backends/neo4j/isDependency.go | 280 -------- pkg/assembler/backends/neo4j/isOccurrence.go | 353 ---------- pkg/assembler/backends/neo4j/path.go | 47 -- pkg/assembler/backends/neo4j/pkg.go | 584 ---------------- pkg/assembler/backends/neo4j/pkgEqual.go | 267 ------- pkg/assembler/backends/neo4j/search.go | 55 -- pkg/assembler/backends/neo4j/src.go | 401 ----------- pkg/assembler/backends/neo4j/vulnEqual.go | 205 ------ pkg/assembler/backends/neo4j/vulnMetadata.go | 39 -- pkg/assembler/backends/neo4j/vulnerability.go | 210 ------ pkg/assembler/backends/neptune/neptune.go | 185 ----- pkg/cli/store.go | 2 +- 40 files changed, 6 insertions(+), 6765 deletions(-) delete mode 100644 container_files/neo4j.yaml delete mode 100644 container_files/neo4j/guac.yaml delete mode 100644 pkg/assembler/backends/neo4j/artifact.go delete mode 100644 pkg/assembler/backends/neo4j/backend.go delete mode 100644 pkg/assembler/backends/neo4j/builder.go delete mode 100644 pkg/assembler/backends/neo4j/certifyBad.go delete mode 100644 pkg/assembler/backends/neo4j/certifyGood.go delete mode 100644 pkg/assembler/backends/neo4j/certifyScorecard.go delete mode 100644 pkg/assembler/backends/neo4j/certifyVEXStatement.go delete mode 100644 pkg/assembler/backends/neo4j/certifyVuln.go delete mode 100644 pkg/assembler/backends/neo4j/contact.go delete mode 100644 pkg/assembler/backends/neo4j/hasMetadata.go delete mode 100644 pkg/assembler/backends/neo4j/hasSBOM.go delete mode 100644 pkg/assembler/backends/neo4j/hasSLSA.go delete mode 100644 pkg/assembler/backends/neo4j/hasSourceAt.go delete mode 100644 pkg/assembler/backends/neo4j/hashEqual.go delete mode 100644 pkg/assembler/backends/neo4j/ingest_testdata.go delete mode 100644 pkg/assembler/backends/neo4j/isDependency.go delete mode 100644 pkg/assembler/backends/neo4j/isOccurrence.go delete mode 100644 pkg/assembler/backends/neo4j/path.go delete mode 100644 pkg/assembler/backends/neo4j/pkg.go delete mode 100644 pkg/assembler/backends/neo4j/pkgEqual.go delete mode 100644 pkg/assembler/backends/neo4j/search.go delete mode 100644 pkg/assembler/backends/neo4j/src.go delete mode 100644 pkg/assembler/backends/neo4j/vulnEqual.go delete mode 100644 pkg/assembler/backends/neo4j/vulnMetadata.go delete mode 100644 pkg/assembler/backends/neo4j/vulnerability.go delete mode 100644 pkg/assembler/backends/neptune/neptune.go diff --git a/.golangci.yaml b/.golangci.yaml index dc8187a0ca..7539a70f5c 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -15,9 +15,5 @@ linters: - path: _test\.go linters: - forcetypeassert # test files use mocks - - path: pkg/assembler/backends/neo4j - linters: - - unused # getting many unused false positives in neo4j backend - - forcetypeassert # this backend does this a lot issues: max-same-issues: 50 diff --git a/Makefile b/Makefile index 419a6e7f5f..4260564a08 100644 --- a/Makefile +++ b/Makefile @@ -159,9 +159,6 @@ container: check-docker-tool-check check-docker-buildx-tool-check check-goreleas # making the container is a longer process and thus not a dependency of service. .PHONY: start-service start-service: check-docker-compose-tool-check - # requires force recreate since docker compose reuses containers and neo4j does - # not handle that well. - # # if container images are missing, run `make container` first $(CONTAINER) compose -f docker-compose.yml -f container_files/mem.yaml up --force-recreate @echo "Waiting for the service to start" diff --git a/README.md b/README.md index c68e3441e7..65ab2939ed 100644 --- a/README.md +++ b/README.md @@ -122,12 +122,6 @@ The other backends are: optimized)](https://github.com/guacsec/guac/tree/main/pkg/assembler/backends/arangodb): a persistent backend based on [ArangoDB](https://arangodb.com/) -- [neo4j/openCypher (unsupported, - incomplete)](https://github.com/guacsec/guac/tree/main/pkg/assembler/backends/neo4j): - a persistent backend based on [neo4j](https://neo4j.com/) and - [openCypher](https://opencypher.org/). This backend should work with any - database that supported openCypher queries. - - [keyvalue: Redis (experimental, complete)](/pkg/assembler/kv/redis): The default keyvalue backend, but using Redis as storage. diff --git a/cmd/README.md b/cmd/README.md index 6c9dd1a679..3291967991 100644 --- a/cmd/README.md +++ b/cmd/README.md @@ -32,8 +32,8 @@ services: - what it does: runs a GraphQL server - options: - - backend: keyvalue, neo4j, arango, ent, or future DB - - backend-specific options: neo4j connection options + - backend: keyvalue, arango, ent, or future DB + - backend-specific options: backend connection options - playground / debug: also start playground **guaccsub** @@ -103,7 +103,7 @@ not required. be short: ex: interval. - Namespaced - If appropriate, group a group of flags that go together with a - prefix, ex: neo4j. + prefix, ex: arango. - Short versions - Service oriented flags don't need short versions, user oriented flags should. diff --git a/cmd/guacgql/cmd/server.go b/cmd/guacgql/cmd/server.go index 48518e3c50..7ed3850efb 100644 --- a/cmd/guacgql/cmd/server.go +++ b/cmd/guacgql/cmd/server.go @@ -37,8 +37,6 @@ import ( _ "github.com/guacsec/guac/pkg/assembler/backends/arangodb" _ "github.com/guacsec/guac/pkg/assembler/backends/ent/backend" _ "github.com/guacsec/guac/pkg/assembler/backends/keyvalue" - _ "github.com/guacsec/guac/pkg/assembler/backends/neo4j" - _ "github.com/guacsec/guac/pkg/assembler/backends/neptune" "github.com/guacsec/guac/pkg/assembler/server" "github.com/guacsec/guac/pkg/logging" "github.com/guacsec/guac/pkg/metrics" diff --git a/container_files/neo4j.yaml b/container_files/neo4j.yaml deleted file mode 100644 index 3f96861943..0000000000 --- a/container_files/neo4j.yaml +++ /dev/null @@ -1,38 +0,0 @@ -version: "3.9" - -services: - - neo4j: - networks: [frontend] - image: "neo4j:4.4.9-community" - environment: - NEO4J_AUTH: "neo4j/s3cr3t" - NEO4J_apoc_export_file_enabled: true - NEO4J_apoc_import_file_enabled: true - NEO4J_apoc_import_file_use__neo4j__config: true - NEO4JLABS_PLUGINS: '["apoc"]' - ports: - - "7474:7474" - - "7687:7687" - restart: on-failure - - - guac-graphql: - networks: [frontend] - image: $GUAC_IMAGE - command: "/opt/guac/guacgql" - working_dir: /guac - restart: on-failure - depends_on: - nats: - condition: service_healthy - ports: - - "$GUAC_API_PORT:8080" - volumes: - - ./container_files/neo4j:/guac:z - healthcheck: - test: ["CMD", "wget", "--spider", "http://localhost:8080"] - interval: 10s - timeout: 10s - retries: 3 - start_period: 5s diff --git a/container_files/neo4j/guac.yaml b/container_files/neo4j/guac.yaml deleted file mode 100644 index 39f3795153..0000000000 --- a/container_files/neo4j/guac.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# pubsub - default nats -pubsub-addr: nats://nats:4222 - -# blob store setup. Setup with blob store of choice via https://gocloud.dev/howto/blob/ -blob-addr: file:///tmp/blobstore?no_tmp_dir=true - -# collect-sub -csub-addr: guac-collectsub:2782 -csub-listen-port: 2782 - -# graphql -gql-backend: neo4j -gql-listen-port: 8080 -gql-debug: true -gql-test-data: false -gql-addr: http://guac-graphql:8080/query - -# collector polling -service-poll: true -use-csub: true - -# certifier polling -poll: true -interval: 5m - -# number of hours since the last scan was run. 0 means run on all packages/sources -last-scan: 4 - -# Neo4j details -neo4j-user: neo4j -neo4j-pass: s3cr3t -neo4j-addr: neo4j://localhost:7687 -neo4j-realm: neo4j diff --git a/go.mod b/go.mod index 661cd77706..c24e86e79a 100644 --- a/go.mod +++ b/go.mod @@ -307,7 +307,6 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/nats-io/nats-server/v2 v2.11.15 github.com/nats-io/nats.go v1.49.0 - github.com/neo4j/neo4j-go-driver/v5 v5.28.4 github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 github.com/oapi-codegen/runtime v1.1.1 github.com/opencontainers/go-digest v1.0.0 diff --git a/go.sum b/go.sum index 63e9c2fb66..9252fb58de 100644 --- a/go.sum +++ b/go.sum @@ -1131,8 +1131,6 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/neo4j/neo4j-go-driver/v5 v5.28.4 h1:7toxehVcYkZbyxV4W3Ib9VcnyRBQPucF+VwNNmtSXi4= -github.com/neo4j/neo4j-go-driver/v5 v5.28.4/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k= github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A= github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= diff --git a/guac.yaml b/guac.yaml index 556e9c4788..9e45af33a3 100644 --- a/guac.yaml +++ b/guac.yaml @@ -1,22 +1,8 @@ -# arangodb +# arangodb arango-user: root arango-pass: test123 arango-addr: http://localhost:8529 -# Neo4j details -neo4j-user: neo4j -neo4j-pass: s3cr3t -neo4j-addr: neo4j://localhost:7687 -neo4j-realm: neo4j - -# Neptune details -# Populate neptune-endpoint, neptune-port and neptune-region with accurate values. -neptune-user: username -neptune-endpoint: localhost -neptune-port: 8182 -neptune-region: us-east-1 -neptune-realm: neptune - # pubsub setup pubsub-addr: nats://localhost:4222 publish-to-queue: true diff --git a/internal/testing/cmd/pubsub_test/cmd/root.go b/internal/testing/cmd/pubsub_test/cmd/root.go index 97137274e6..66411d9bd3 100644 --- a/internal/testing/cmd/pubsub_test/cmd/root.go +++ b/internal/testing/cmd/pubsub_test/cmd/root.go @@ -30,11 +30,6 @@ import ( var cfgFile string var flags = struct { - dbAddr string - gdbuser string - gdbpass string - realm string - // nats pubsubAddr string @@ -46,16 +41,12 @@ var flags = struct { func init() { cobra.OnInitialize(initConfig) persistentFlags := rootCmd.PersistentFlags() - persistentFlags.StringVar(&flags.dbAddr, "gdbaddr", "neo4j://localhost:7687", "address to neo4j db") - persistentFlags.StringVar(&flags.gdbuser, "gdbuser", "", "neo4j user credential to connect to graph db") - persistentFlags.StringVar(&flags.gdbpass, "gdbpass", "", "neo4j password credential to connect to graph db") - persistentFlags.StringVar(&flags.realm, "realm", "neo4j", "realm to connect to graph db") persistentFlags.StringVar(&flags.pubsubAddr, "pubsubAddr", "nats://127.0.0.1:4222", "address to connect to NATs Server") // certifier flags persistentFlags.BoolVarP(&flags.poll, "poll", "p", true, "sets the certifier to polling mode") persistentFlags.IntVarP(&flags.interval, "interval", "i", 5, "if polling set interval in minutes") - flagNames := []string{"gdbaddr", "gdbuser", "gdbpass", "realm", "pubsubAddr", "poll", "interval"} + flagNames := []string{"pubsubAddr", "poll", "interval"} for _, name := range flagNames { if flag := persistentFlags.Lookup(name); flag != nil { if err := viper.BindPFlag(name, flag); err != nil { diff --git a/pkg/assembler/backends/README.md b/pkg/assembler/backends/README.md index 06417fdfa7..4d5a8b33b8 100644 --- a/pkg/assembler/backends/README.md +++ b/pkg/assembler/backends/README.md @@ -17,6 +17,5 @@ project. ## Backends - `arangodb/`: Backend based on the Arango database -- `neo4j/`: Backend based on the Neo4j database - `testing/`: simple backend with no resolvers implemented. Useful for prototyping. Also known as the in-memory backend. diff --git a/pkg/assembler/backends/arangodb/pkg.go b/pkg/assembler/backends/arangodb/pkg.go index 0e81a06e9e..e80cdcde5c 100644 --- a/pkg/assembler/backends/arangodb/pkg.go +++ b/pkg/assembler/backends/arangodb/pkg.go @@ -781,8 +781,6 @@ func getFilterQualifiers(qualifiersSpec []*model.PackageQualifierSpec) []string } func removeInvalidCharFromProperty(key string) string { - // neo4j does not accept "." in its properties. If the qualifier contains a "." that must - // be replaced by an "-" return strings.ReplaceAll(key, ".", "_") } diff --git a/pkg/assembler/backends/neo4j/artifact.go b/pkg/assembler/backends/neo4j/artifact.go deleted file mode 100644 index af0ff12cd2..0000000000 --- a/pkg/assembler/backends/neo4j/artifact.go +++ /dev/null @@ -1,145 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" -) - -func (c *neo4jClient) Artifacts(ctx context.Context, artifactSpec *model.ArtifactSpec) ([]*model.Artifact, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - sb.WriteString("MATCH (a:Artifact)") - - setArtifactMatchValues(&sb, artifactSpec, false, &firstMatch, queryValues) - - sb.WriteString(" RETURN a.algorithm, a.digest") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - artifacts := []*model.Artifact{} - for result.Next() { - algorithm := result.Record().Values[0].(string) - digest := result.Record().Values[1].(string) - artifact := generateModelArtifact(algorithm, digest) - artifacts = append(artifacts, artifact) - } - if err = result.Err(); err != nil { - return nil, err - } - - return artifacts, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.Artifact), nil -} - -func (c *neo4jClient) IngestArtifacts(ctx context.Context, artifacts []*model.IDorArtifactInput) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestArtifacts") -} - -func (c *neo4jClient) IngestArtifact(ctx context.Context, artifact *model.IDorArtifactInput) (string, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) - defer session.Close() - - values := map[string]any{} - values["algorithm"] = strings.ToLower(artifact.ArtifactInput.Algorithm) - values["digest"] = strings.ToLower(artifact.ArtifactInput.Digest) - - result, err := session.WriteTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - query := ` -MERGE (a:Artifact{algorithm:$algorithm,digest:$digest}) -RETURN a.algorithm, a.digest` - result, err := tx.Run(query, values) - if err != nil { - return nil, err - } - - // query returns a single record - record, err := result.Single() - if err != nil { - return nil, err - } - - algorithm := record.Values[0].(string) - digest := record.Values[1].(string) - artifact := generateModelArtifact(algorithm, digest) - - return artifact, nil - }) - if err != nil { - return "", err - } - - return result.(*model.Artifact).ID, nil -} - -func setArtifactMatchValues(sb *strings.Builder, art *model.ArtifactSpec, objectArt bool, firstMatch *bool, queryValues map[string]any) { - if art != nil { - if art.Algorithm != nil { - if !objectArt { - matchProperties(sb, *firstMatch, "a", "algorithm", "$algorithm") - queryValues["algorithm"] = strings.ToLower(*art.Algorithm) - } else { - matchProperties(sb, *firstMatch, "objArt", "algorithm", "$objAlgorithm") - queryValues["objAlgorithm"] = strings.ToLower(*art.Algorithm) - } - *firstMatch = false - } - - if art.Digest != nil { - if !objectArt { - matchProperties(sb, *firstMatch, "a", "digest", "$digest") - queryValues["digest"] = strings.ToLower(*art.Digest) - } else { - matchProperties(sb, *firstMatch, "objArt", "digest", "$objDigest") - queryValues["objDigest"] = strings.ToLower(*art.Digest) - } - *firstMatch = false - } - } -} - -func generateModelArtifact(algorithm, digest string) *model.Artifact { - artifact := model.Artifact{ - Algorithm: algorithm, - Digest: digest, - } - return &artifact -} - -func (c *neo4jClient) ArtifactsList(ctx context.Context, artifactSpec model.ArtifactSpec, after *string, first *int) (*model.ArtifactConnection, error) { - return nil, fmt.Errorf("not implemented: ArtifactsList") -} diff --git a/pkg/assembler/backends/neo4j/backend.go b/pkg/assembler/backends/neo4j/backend.go deleted file mode 100644 index 7f1c278d6b..0000000000 --- a/pkg/assembler/backends/neo4j/backend.go +++ /dev/null @@ -1,187 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - - "github.com/guacsec/guac/pkg/assembler/backends" - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -const ( - namespaces string = "namespaces" - names string = namespaces + ".names" - versions string = names + ".versions" - cvdID string = "cveId" - origin string = "origin" - collector string = "collector" - justification string = "justification" - status string = "status" - statement string = "statement" - statusNotes string = "statusNotes" -) - -type Neo4jConfig struct { - User string - Pass string - Realm string - DBAddr string - TestData bool -} - -type neo4jClient struct { - driver neo4j.Driver -} - -// flags holds the command-line flags for Neo4j configuration -var flags = struct { - addr string - user string - pass string - realm string -}{} - -func init() { - backends.Register("neo4j", getBackend, registerFlags, parseFlags) -} - -// registerFlags registers Neo4j-specific command line flags -func registerFlags(cmd *cobra.Command) error { - flagSet := cmd.Flags() - flagSet.StringVar(&flags.addr, "neo4j-addr", "neo4j://localhost:7687", "address to neo4j db") - flagSet.StringVar(&flags.user, "neo4j-user", "", "neo4j user credential to connect to graph db") - flagSet.StringVar(&flags.pass, "neo4j-pass", "", "neo4j password credential to connect to graph db") - flagSet.StringVar(&flags.realm, "neo4j-realm", "neo4j", "realm to connect to graph db") - - if err := viper.BindPFlags(flagSet); err != nil { - return fmt.Errorf("failed to bind flags: %w", err) - } - - // set values from guac.yaml if present - flags.user = viper.GetString("neo4j-user") - flags.pass = viper.GetString("neo4j-pass") - flags.addr = viper.GetString("neo4j-addr") - flags.realm = viper.GetString("neo4j-realm") - - return nil -} - -// parseFlags returns the Neo4j configuration from parsed flags -func parseFlags(ctx context.Context) (backends.BackendArgs, error) { - return &Neo4jConfig{ - DBAddr: flags.addr, - User: flags.user, - Pass: flags.pass, - Realm: flags.realm, - }, nil -} - -func getBackend(_ context.Context, args backends.BackendArgs) (backends.Backend, error) { - config, ok := args.(*Neo4jConfig) - if !ok { - return nil, fmt.Errorf("failed to assert neo4j config from backend args") - } - token := neo4j.BasicAuth(config.User, config.Pass, config.Realm) - driver, err := neo4j.NewDriver(config.DBAddr, token) - if err != nil { - return nil, err - } - - if err = driver.VerifyConnectivity(); err != nil { - driver.Close() - return nil, err - } - client := &neo4jClient{driver: driver} - /* if config.TestData { - err = registerAllPackages(client) - if err != nil { - return nil, err - } - err = registerAllArtifacts(client) - if err != nil { - return nil, err - } - err = registerAllBuilders(client) - if err != nil { - return nil, err - } - err = registerAllSources(client) - if err != nil { - return nil, err - } - err = registerAllCVE(client) - if err != nil { - return nil, err - } - err = registerAllGHSA(client) - if err != nil { - return nil, err - } - err = registerAllOSV(client) - if err != nil { - return nil, err - } - } */ - return client, nil -} - -func matchProperties(sb *strings.Builder, firstMatch bool, label, property string, resolver string) { - if firstMatch { - sb.WriteString(" WHERE ") - } else { - sb.WriteString(" AND ") - } - sb.WriteString(label) - sb.WriteString(".") - sb.WriteString(property) - sb.WriteString(" = ") - sb.WriteString(resolver) -} - -func (c *neo4jClient) Licenses(ctx context.Context, licenseSpec *model.LicenseSpec) ([]*model.License, error) { - panic(fmt.Errorf("not implemented: Licenses")) -} - -func (c *neo4jClient) LicenseList(ctx context.Context, licenseSpec model.LicenseSpec, after *string, first *int) (*model.LicenseConnection, error) { - panic(fmt.Errorf("not implemented: LicenseList")) -} - -func (c *neo4jClient) IngestLicense(ctx context.Context, license *model.IDorLicenseInput) (string, error) { - panic(fmt.Errorf("not implemented: IngestLicense")) -} -func (c *neo4jClient) IngestLicenses(ctx context.Context, licenses []*model.IDorLicenseInput) ([]string, error) { - panic(fmt.Errorf("not implemented: IngestLicenses")) -} - -func (c *neo4jClient) CertifyLegalList(ctx context.Context, certifyLegalSpec model.CertifyLegalSpec, after *string, first *int) (*model.CertifyLegalConnection, error) { - panic(fmt.Errorf("not implemented: CertifyLegalList")) -} - -func (c *neo4jClient) CertifyLegal(ctx context.Context, certifyLegalSpec *model.CertifyLegalSpec) ([]*model.CertifyLegal, error) { - panic(fmt.Errorf("not implemented: CertifyLegal")) -} -func (c *neo4jClient) IngestCertifyLegal(ctx context.Context, subject model.PackageOrSourceInput, declaredLicenses []*model.IDorLicenseInput, discoveredLicenses []*model.IDorLicenseInput, certifyLegal *model.CertifyLegalInputSpec) (string, error) { - panic(fmt.Errorf("not implemented: IngestCertifyLegal")) -} -func (c *neo4jClient) IngestCertifyLegals(ctx context.Context, subjects model.PackageOrSourceInputs, declaredLicensesList [][]*model.IDorLicenseInput, discoveredLicensesList [][]*model.IDorLicenseInput, certifyLegals []*model.CertifyLegalInputSpec) ([]string, error) { - panic(fmt.Errorf("not implemented: IngestCertifyLegals")) -} diff --git a/pkg/assembler/backends/neo4j/builder.go b/pkg/assembler/backends/neo4j/builder.go deleted file mode 100644 index fb1dc34c86..0000000000 --- a/pkg/assembler/backends/neo4j/builder.go +++ /dev/null @@ -1,110 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" -) - -func (c *neo4jClient) BuildersList(ctx context.Context, builderSpec model.BuilderSpec, after *string, first *int) (*model.BuilderConnection, error) { - return nil, fmt.Errorf("not implemented: BuildersList") -} - -func (c *neo4jClient) Builders(ctx context.Context, builderSpec *model.BuilderSpec) ([]*model.Builder, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var query string - values := map[string]any{} - if builderSpec.URI != nil { - query = "MATCH (b:Builder) WHERE b.uri = $uri RETURN b.uri" - values["uri"] = *builderSpec.URI - } else { - query = "MATCH (b:Builder) RETURN b.uri" - } - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(query, values) - if err != nil { - return nil, err - } - - builders := []*model.Builder{} - for result.Next() { - uri := result.Record().Values[0].(string) - builder := generateModelBuilder(uri) - builders = append(builders, builder) - } - if err = result.Err(); err != nil { - return nil, err - } - - return builders, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.Builder), nil -} - -func (c *neo4jClient) IngestBuilders(ctx context.Context, builders []*model.IDorBuilderInput) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestBuilders") -} - -func (c *neo4jClient) IngestBuilder(ctx context.Context, builder *model.IDorBuilderInput) (string, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) - defer session.Close() - - values := map[string]any{} - values["uri"] = builder.BuilderInput.URI - - result, err := session.WriteTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - query := "MERGE (b:Builder{uri:$uri}) RETURN b.uri" - result, err := tx.Run(query, values) - if err != nil { - return nil, err - } - - // query returns a single record - record, err := result.Single() - if err != nil { - return nil, err - } - uri := record.Values[0].(string) - builder := generateModelBuilder(uri) - - return builder, nil - }) - if err != nil { - return "", err - } - - return result.(*model.Builder).ID, nil -} - -func generateModelBuilder(uri string) *model.Builder { - builder := model.Builder{ - URI: uri, - } - return &builder -} diff --git a/pkg/assembler/backends/neo4j/certifyBad.go b/pkg/assembler/backends/neo4j/certifyBad.go deleted file mode 100644 index 00d806e7ed..0000000000 --- a/pkg/assembler/backends/neo4j/certifyBad.go +++ /dev/null @@ -1,276 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -// query certifyBad - -func (c *neo4jClient) CertifyBadList(ctx context.Context, certifyBadSpec model.CertifyBadSpec, after *string, first *int) (*model.CertifyBadConnection, error) { - return nil, fmt.Errorf("not implemented: CertifyBadList") -} - -func (c *neo4jClient) CertifyBad(ctx context.Context, certifyBadSpec *model.CertifyBadSpec) ([]*model.CertifyBad, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - // TODO: Fix validation - queryAll := true - // queryAll, err := helper.ValidatePackageSourceOrArtifactQueryInput(certifyBadSpec.Subject) - // if err != nil { - // return nil, err - // } - - aggregateCertifyBad := []*model.CertifyBad{} - - if queryAll || (certifyBadSpec.Subject != nil && certifyBadSpec.Subject.Package != nil) { - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - "version.qualifier_list, certifyBad" - // query with pkgVersion - query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - "-[:subject]-(certifyBad:CertifyBad)" - sb.WriteString(query) - - if certifyBadSpec.Subject != nil && certifyBadSpec.Subject.Package != nil { - setPkgMatchValues(&sb, certifyBadSpec.Subject.Package, false, &firstMatch, queryValues) - } - setCertifyBadValues(&sb, certifyBadSpec, &firstMatch, queryValues) - sb.WriteString(returnValue) - - if certifyBadSpec.Subject.Package == nil || certifyBadSpec.Subject.Package != nil && certifyBadSpec.Subject.Package.Version == nil && - certifyBadSpec.Subject.Package.Subpath == nil && len(certifyBadSpec.Subject.Package.Qualifiers) == 0 && - !*certifyBadSpec.Subject.Package.MatchOnlyEmptyQualifiers { - - sb.WriteString("\nUNION") - // query without pkgVersion - query = "\nMATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:subject]-(certifyBad:CertifyBad)" + - "\nWITH *, null AS version" - sb.WriteString(query) - - firstMatch = true - - if certifyBadSpec.Subject != nil && certifyBadSpec.Subject.Package != nil { - setPkgMatchValues(&sb, certifyBadSpec.Subject.Package, false, &firstMatch, queryValues) - } - setCertifyBadValues(&sb, certifyBadSpec, &firstMatch, queryValues) - sb.WriteString(returnValue) - } - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedCertifyBad := []*model.CertifyBad{} - - for result.Next() { - pkgQualifiers := result.Record().Values[5] - subPath := result.Record().Values[4] - version := result.Record().Values[3] - nameString := result.Record().Values[2].(string) - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - certifyBadNode := dbtype.Node{} - if result.Record().Values[6] != nil { - certifyBadNode = result.Record().Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("certifyBad Node not found in neo4j") - } - - certifyBad := generateModelCertifyBad(pkg, certifyBadNode.Props[justification].(string), certifyBadNode.Props[origin].(string), certifyBadNode.Props[collector].(string)) - - collectedCertifyBad = append(collectedCertifyBad, certifyBad) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedCertifyBad, nil - }) - if err != nil { - return nil, err - } - - aggregateCertifyBad = append(aggregateCertifyBad, result.([]*model.CertifyBad)...) - } - - if queryAll || (certifyBadSpec.Subject != nil && certifyBadSpec.Subject.Source != nil) { - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - query := "MATCH (root:Src)-[:SrcHasType]->(type:SrcType)-[:SrcHasNamespace]->(namespace:SrcNamespace)" + - "-[:SrcHasName]->(name:SrcName)-[:subject]-(certifyBad:CertifyBad)" - sb.WriteString(query) - - if certifyBadSpec.Subject != nil && certifyBadSpec.Subject.Source != nil { - setSrcMatchValues(&sb, certifyBadSpec.Subject.Source, false, &firstMatch, queryValues) - } - setCertifyBadValues(&sb, certifyBadSpec, &firstMatch, queryValues) - sb.WriteString(" RETURN type.type, namespace.namespace, name.name, name.tag, name.commit, certifyBad") - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedCertifyBad := []*model.CertifyBad{} - - for result.Next() { - tag := result.Record().Values[3] - commit := result.Record().Values[4] - nameStr := result.Record().Values[2].(string) - namespaceStr := result.Record().Values[1].(string) - srcType := result.Record().Values[0].(string) - - src := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - certifyBadNode := dbtype.Node{} - if result.Record().Values[5] != nil { - certifyBadNode = result.Record().Values[5].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("certifyBad Node not found in neo4j") - } - - certifyBad := generateModelCertifyBad(src, certifyBadNode.Props[justification].(string), certifyBadNode.Props[origin].(string), certifyBadNode.Props[collector].(string)) - - collectedCertifyBad = append(collectedCertifyBad, certifyBad) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedCertifyBad, nil - }) - if err != nil { - return nil, err - } - aggregateCertifyBad = append(aggregateCertifyBad, result.([]*model.CertifyBad)...) - } - - if queryAll || (certifyBadSpec.Subject != nil && certifyBadSpec.Subject.Artifact != nil) { - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - query := "MATCH (a:Artifact)-[:subject]-(certifyBad:CertifyBad)" - sb.WriteString(query) - - if certifyBadSpec.Subject != nil && certifyBadSpec.Subject.Artifact != nil { - setArtifactMatchValues(&sb, certifyBadSpec.Subject.Artifact, false, &firstMatch, queryValues) - } - setCertifyBadValues(&sb, certifyBadSpec, &firstMatch, queryValues) - sb.WriteString(" RETURN a.algorithm, a.digest, certifyBad") - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedCertifyBad := []*model.CertifyBad{} - - for result.Next() { - algorithm := result.Record().Values[0].(string) - digest := result.Record().Values[1].(string) - artifact := generateModelArtifact(algorithm, digest) - - certifyBadNode := dbtype.Node{} - if result.Record().Values[2] != nil { - certifyBadNode = result.Record().Values[2].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("certifyBad Node not found in neo4j") - } - - certifyBad := generateModelCertifyBad(artifact, certifyBadNode.Props[justification].(string), certifyBadNode.Props[origin].(string), certifyBadNode.Props[collector].(string)) - collectedCertifyBad = append(collectedCertifyBad, certifyBad) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedCertifyBad, nil - }) - if err != nil { - return nil, err - } - - aggregateCertifyBad = append(aggregateCertifyBad, result.([]*model.CertifyBad)...) - } - return aggregateCertifyBad, nil - -} - -func setCertifyBadValues(sb *strings.Builder, certifyBadSpec *model.CertifyBadSpec, firstMatch *bool, queryValues map[string]any) { - if certifyBadSpec.Justification != nil { - matchProperties(sb, *firstMatch, "certifyBad", "justification", "$justification") - *firstMatch = false - queryValues["justification"] = certifyBadSpec.Justification - } - if certifyBadSpec.Origin != nil { - matchProperties(sb, *firstMatch, "certifyBad", "origin", "$origin") - *firstMatch = false - queryValues["origin"] = certifyBadSpec.Origin - } - if certifyBadSpec.Collector != nil { - matchProperties(sb, *firstMatch, "certifyBad", "collector", "$collector") - *firstMatch = false - queryValues["collector"] = certifyBadSpec.Collector - } -} - -func generateModelCertifyBad(subject model.PackageSourceOrArtifact, justification, origin, collector string) *model.CertifyBad { - certifyBad := model.CertifyBad{ - Subject: subject, - Justification: justification, - Origin: origin, - Collector: collector, - } - return &certifyBad -} - -// ingest certifyBad - -func (c *neo4jClient) IngestCertifyBad(ctx context.Context, subject model.PackageSourceOrArtifactInput, pkgMatchType *model.MatchFlags, certifyBad model.CertifyBadInputSpec) (string, error) { - panic(fmt.Errorf("not implemented: IngestCertifyBad - IngestCertifyBad")) -} - -func (c *neo4jClient) IngestCertifyBads(ctx context.Context, subjects model.PackageSourceOrArtifactInputs, pkgMatchType *model.MatchFlags, certifyBads []*model.CertifyBadInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestCertifyBads") -} diff --git a/pkg/assembler/backends/neo4j/certifyGood.go b/pkg/assembler/backends/neo4j/certifyGood.go deleted file mode 100644 index ee752d797c..0000000000 --- a/pkg/assembler/backends/neo4j/certifyGood.go +++ /dev/null @@ -1,270 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -// query certifyGood - -func (c *neo4jClient) CertifyGoodList(ctx context.Context, certifyGoodSpec model.CertifyGoodSpec, after *string, first *int) (*model.CertifyGoodConnection, error) { - return nil, fmt.Errorf("not implemented: BuildersList") -} - -func (c *neo4jClient) CertifyGood(ctx context.Context, certifyGoodSpec *model.CertifyGoodSpec) ([]*model.CertifyGood, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - queryAll := true - aggregateCertifyGood := []*model.CertifyGood{} - - if queryAll || (certifyGoodSpec.Subject != nil && certifyGoodSpec.Subject.Package != nil) { - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - "version.qualifier_list, certifyGood" - // query with pkgVersion - query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - "-[:subject]-(certifyGood:CertifyGood)" - sb.WriteString(query) - - if certifyGoodSpec.Subject != nil && certifyGoodSpec.Subject.Package != nil { - setPkgMatchValues(&sb, certifyGoodSpec.Subject.Package, false, &firstMatch, queryValues) - } - setCertifyGoodValues(&sb, certifyGoodSpec, &firstMatch, queryValues) - sb.WriteString(returnValue) - - if certifyGoodSpec.Subject.Package == nil || certifyGoodSpec.Subject.Package != nil && certifyGoodSpec.Subject.Package.Version == nil && - certifyGoodSpec.Subject.Package.Subpath == nil && len(certifyGoodSpec.Subject.Package.Qualifiers) == 0 && - !*certifyGoodSpec.Subject.Package.MatchOnlyEmptyQualifiers { - - sb.WriteString("\nUNION") - // query without pkgVersion - query = "\nMATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:subject]-(certifyGood:CertifyGood)" + - "\nWITH *, null AS version" - sb.WriteString(query) - - firstMatch = true - - if certifyGoodSpec.Subject != nil && certifyGoodSpec.Subject.Package != nil { - setPkgMatchValues(&sb, certifyGoodSpec.Subject.Package, false, &firstMatch, queryValues) - } - setCertifyGoodValues(&sb, certifyGoodSpec, &firstMatch, queryValues) - sb.WriteString(returnValue) - } - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedCertifyGood := []*model.CertifyGood{} - - for result.Next() { - pkgQualifiers := result.Record().Values[5] - subPath := result.Record().Values[4] - version := result.Record().Values[3] - nameString := result.Record().Values[2].(string) - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - certifyGoodNode := dbtype.Node{} - if result.Record().Values[6] != nil { - certifyGoodNode = result.Record().Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("certifyGood Node not found in neo4j") - } - - certifyGood := generateModelCertifyGood(pkg, certifyGoodNode.Props[justification].(string), certifyGoodNode.Props[origin].(string), certifyGoodNode.Props[collector].(string)) - - collectedCertifyGood = append(collectedCertifyGood, certifyGood) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedCertifyGood, nil - }) - if err != nil { - return nil, err - } - - aggregateCertifyGood = append(aggregateCertifyGood, result.([]*model.CertifyGood)...) - } - - if queryAll || (certifyGoodSpec.Subject != nil && certifyGoodSpec.Subject.Source != nil) { - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - query := "MATCH (root:Src)-[:SrcHasType]->(type:SrcType)-[:SrcHasNamespace]->(namespace:SrcNamespace)" + - "-[:SrcHasName]->(name:SrcName)-[:subject]-(certifyGood:CertifyGood)" - sb.WriteString(query) - - if certifyGoodSpec.Subject != nil && certifyGoodSpec.Subject.Source != nil { - setSrcMatchValues(&sb, certifyGoodSpec.Subject.Source, false, &firstMatch, queryValues) - } - setCertifyGoodValues(&sb, certifyGoodSpec, &firstMatch, queryValues) - sb.WriteString(" RETURN type.type, namespace.namespace, name.name, name.tag, name.commit, certifyGood") - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedCertifyGood := []*model.CertifyGood{} - - for result.Next() { - tag := result.Record().Values[3] - commit := result.Record().Values[4] - nameStr := result.Record().Values[2].(string) - namespaceStr := result.Record().Values[1].(string) - srcType := result.Record().Values[0].(string) - - src := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - certifyGoodNode := dbtype.Node{} - if result.Record().Values[5] != nil { - certifyGoodNode = result.Record().Values[5].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("certifyGood Node not found in neo4j") - } - - certifyGood := generateModelCertifyGood(src, certifyGoodNode.Props[justification].(string), certifyGoodNode.Props[origin].(string), certifyGoodNode.Props[collector].(string)) - - collectedCertifyGood = append(collectedCertifyGood, certifyGood) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedCertifyGood, nil - }) - if err != nil { - return nil, err - } - aggregateCertifyGood = append(aggregateCertifyGood, result.([]*model.CertifyGood)...) - } - - if queryAll || (certifyGoodSpec.Subject != nil && certifyGoodSpec.Subject.Artifact != nil) { - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - query := "MATCH (a:Artifact)-[:subject]-(certifyGood:CertifyGood)" - sb.WriteString(query) - - if certifyGoodSpec.Subject != nil && certifyGoodSpec.Subject.Artifact != nil { - setArtifactMatchValues(&sb, certifyGoodSpec.Subject.Artifact, false, &firstMatch, queryValues) - } - setCertifyGoodValues(&sb, certifyGoodSpec, &firstMatch, queryValues) - sb.WriteString(" RETURN a.algorithm, a.digest, certifyGood") - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedCertifyGood := []*model.CertifyGood{} - - for result.Next() { - algorithm := result.Record().Values[0].(string) - digest := result.Record().Values[1].(string) - artifact := generateModelArtifact(algorithm, digest) - - certifyGoodNode := dbtype.Node{} - if result.Record().Values[2] != nil { - certifyGoodNode = result.Record().Values[2].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("certifyGood Node not found in neo4j") - } - - certifyGood := generateModelCertifyGood(artifact, certifyGoodNode.Props[justification].(string), certifyGoodNode.Props[origin].(string), certifyGoodNode.Props[collector].(string)) - collectedCertifyGood = append(collectedCertifyGood, certifyGood) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedCertifyGood, nil - }) - if err != nil { - return nil, err - } - - aggregateCertifyGood = append(aggregateCertifyGood, result.([]*model.CertifyGood)...) - } - return aggregateCertifyGood, nil - -} - -func setCertifyGoodValues(sb *strings.Builder, certifyGoodSpec *model.CertifyGoodSpec, firstMatch *bool, queryValues map[string]any) { - if certifyGoodSpec.Justification != nil { - matchProperties(sb, *firstMatch, "certifyGood", "justification", "$justification") - *firstMatch = false - queryValues["justification"] = certifyGoodSpec.Justification - } - if certifyGoodSpec.Origin != nil { - matchProperties(sb, *firstMatch, "certifyGood", "origin", "$origin") - *firstMatch = false - queryValues["origin"] = certifyGoodSpec.Origin - } - if certifyGoodSpec.Collector != nil { - matchProperties(sb, *firstMatch, "certifyGood", "collector", "$collector") - *firstMatch = false - queryValues["collector"] = certifyGoodSpec.Collector - } -} - -func generateModelCertifyGood(subject model.PackageSourceOrArtifact, justification, origin, collector string) *model.CertifyGood { - certifyGood := model.CertifyGood{ - Subject: subject, - Justification: justification, - Origin: origin, - Collector: collector, - } - return &certifyGood -} - -// ingest certifyGood - -func (c *neo4jClient) IngestCertifyGood(ctx context.Context, subject model.PackageSourceOrArtifactInput, pkgMatchType *model.MatchFlags, certifyGood model.CertifyGoodInputSpec) (string, error) { - panic(fmt.Errorf("not implemented: IngestCertifyGood - IngestCertifyGood")) -} - -func (c *neo4jClient) IngestCertifyGoods(ctx context.Context, subjects model.PackageSourceOrArtifactInputs, pkgMatchType *model.MatchFlags, certifyGoods []*model.CertifyGoodInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestCertifyGoods") -} diff --git a/pkg/assembler/backends/neo4j/certifyScorecard.go b/pkg/assembler/backends/neo4j/certifyScorecard.go deleted file mode 100644 index 5dd7f780df..0000000000 --- a/pkg/assembler/backends/neo4j/certifyScorecard.go +++ /dev/null @@ -1,313 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "sort" - "strings" - "time" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -const ( - timeScanned string = "timeScanned" - aggregateScore string = "aggregateScore" - checkKeys string = "checkKeys" - checkValues string = "checkValues" - scorecardVersion string = "scorecardVersion" - scorecardCommit string = "scorecardCommit" -) - -// Query Scorecards - -func (c *neo4jClient) ScorecardsList(ctx context.Context, scorecardSpec model.CertifyScorecardSpec, after *string, first *int) (*model.CertifyScorecardConnection, error) { - return nil, fmt.Errorf("not implemented: BuildersList") -} - -func (c *neo4jClient) Scorecards(ctx context.Context, certifyScorecardSpec *model.CertifyScorecardSpec) ([]*model.CertifyScorecard, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - query := "MATCH (root:Src)-[:SrcHasType]->(type:SrcType)-[:SrcHasNamespace]->(namespace:SrcNamespace)" + - "-[:SrcHasName]->(name:SrcName)-[:subject]-(certifyScorecard:CertifyScorecard)" - sb.WriteString(query) - - setSrcMatchValues(&sb, certifyScorecardSpec.Source, false, &firstMatch, queryValues) - setCertifyScorecardValues(&sb, certifyScorecardSpec, &firstMatch, queryValues) - sb.WriteString(" RETURN type.type, namespace.namespace, name.name, name.tag, name.commit, certifyScorecard") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedCertifyScorecard := []*model.CertifyScorecard{} - - for result.Next() { - tag := result.Record().Values[4] - commit := result.Record().Values[3] - nameStr := result.Record().Values[2].(string) - namespaceStr := result.Record().Values[1].(string) - srcType := result.Record().Values[0].(string) - - src := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - certifyScorecardNode := dbtype.Node{} - if result.Record().Values[5] != nil { - certifyScorecardNode = result.Record().Values[5].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("certifyScorecard Node not found in neo4j") - } - - checks, err := getCollectedChecks(certifyScorecardNode.Props[checkKeys].([]interface{}), certifyScorecardNode.Props[checkValues].([]interface{})) - if err != nil { - return nil, err - } - - scorecard := model.Scorecard{ - TimeScanned: certifyScorecardNode.Props[timeScanned].(time.Time), - AggregateScore: certifyScorecardNode.Props[aggregateScore].(float64), - Checks: checks, - ScorecardVersion: certifyScorecardNode.Props[scorecardVersion].(string), - ScorecardCommit: certifyScorecardNode.Props[scorecardCommit].(string), - Origin: certifyScorecardNode.Props[origin].(string), - Collector: certifyScorecardNode.Props[collector].(string), - } - - certifyScorecard := &model.CertifyScorecard{ - Source: src, - Scorecard: &scorecard, - } - - collectedCertifyScorecard = append(collectedCertifyScorecard, certifyScorecard) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedCertifyScorecard, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.CertifyScorecard), nil -} - -func getCollectedChecks(keyList []interface{}, valueList []interface{}) ([]*model.ScorecardCheck, error) { - if len(keyList) != len(valueList) { - return nil, gqlerror.Errorf("length of scorecard checks do not match") - } - checks := []*model.ScorecardCheck{} - for i := range keyList { - check := &model.ScorecardCheck{ - Check: keyList[i].(string), - // TODO(mihaimaruseac): This cast seems weird, investigate - Score: int(valueList[i].(int64)), - } - checks = append(checks, check) - } - return checks, nil -} - -func getScorecardChecks(checks []*model.ScorecardCheckSpec) ([]string, []int) { - checksMap := map[string]int{} - keys := []string{} - for _, kv := range checks { - key := removeInvalidCharFromProperty(kv.Check) - checksMap[key] = kv.Score - keys = append(keys, key) - } - sort.Strings(keys) - collectedChecks := []int{} - for _, k := range keys { - collectedChecks = append(collectedChecks, checksMap[k]) - } - return keys, collectedChecks -} - -func setCertifyScorecardValues(sb *strings.Builder, certifyScorecardSpec *model.CertifyScorecardSpec, firstMatch *bool, queryValues map[string]any) { - if certifyScorecardSpec.TimeScanned != nil { - matchProperties(sb, *firstMatch, "certifyScorecard", timeScanned, "$"+timeScanned) - *firstMatch = false - queryValues[timeScanned] = certifyScorecardSpec.TimeScanned.UTC() - } - if certifyScorecardSpec.AggregateScore != nil { - matchProperties(sb, *firstMatch, "certifyScorecard", aggregateScore, "$"+aggregateScore) - *firstMatch = false - queryValues[aggregateScore] = certifyScorecardSpec.AggregateScore - } - if len(certifyScorecardSpec.Checks) > 0 { - keys, values := getScorecardChecks(certifyScorecardSpec.Checks) - matchProperties(sb, *firstMatch, "certifyScorecard", checkKeys, "$"+checkKeys) - queryValues[checkKeys] = keys - matchProperties(sb, *firstMatch, "certifyScorecard", checkValues, "$"+checkValues) - queryValues[checkValues] = values - *firstMatch = false - } - if certifyScorecardSpec.ScorecardVersion != nil { - matchProperties(sb, *firstMatch, "certifyScorecard", scorecardVersion, "$"+scorecardVersion) - *firstMatch = false - queryValues[scorecardVersion] = certifyScorecardSpec.ScorecardVersion - } - if certifyScorecardSpec.ScorecardCommit != nil { - matchProperties(sb, *firstMatch, "certifyScorecard", scorecardCommit, "$"+scorecardCommit) - *firstMatch = false - queryValues[scorecardCommit] = certifyScorecardSpec.ScorecardCommit - } - if certifyScorecardSpec.Origin != nil { - matchProperties(sb, *firstMatch, "certifyScorecard", "origin", "$origin") - *firstMatch = false - queryValues["origin"] = certifyScorecardSpec.Origin - } - if certifyScorecardSpec.Collector != nil { - matchProperties(sb, *firstMatch, "certifyScorecard", "collector", "$collector") - *firstMatch = false - queryValues["collector"] = certifyScorecardSpec.Collector - } -} - -// Ingest Scorecards - -func (c *neo4jClient) IngestScorecards(ctx context.Context, sources []*model.IDorSourceInput, scorecards []*model.ScorecardInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestScorecards") -} - -// Ingest Scorecard - -func (c *neo4jClient) IngestScorecard(ctx context.Context, source model.IDorSourceInput, scorecard model.ScorecardInputSpec) (string, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) - defer session.Close() - - values := map[string]any{} - values["sourceType"] = source.SourceInput.Type - values["namespace"] = source.SourceInput.Namespace - values["name"] = source.SourceInput.Name - - if source.SourceInput.Commit != nil && source.SourceInput.Tag != nil { - if *source.SourceInput.Commit != "" && *source.SourceInput.Tag != "" { - return "", gqlerror.Errorf("Passing both commit and tag selectors is an error") - } - } - - if source.SourceInput.Commit != nil { - values["commit"] = *source.SourceInput.Commit - } else { - values["commit"] = "" - } - - if source.SourceInput.Tag != nil { - values["tag"] = *source.SourceInput.Tag - } else { - values["tag"] = "" - } - - values[timeScanned] = scorecard.TimeScanned.UTC() - values[aggregateScore] = scorecard.AggregateScore - values[scorecardVersion] = scorecard.ScorecardVersion - values[scorecardCommit] = scorecard.ScorecardCommit - - // Cannot use getScorecardChecks due to type mismatch - // Generics would be really helpful here :) - checksMap := map[string]int{} - checkKeysList := []string{} - checkValuesList := []int{} - for _, check := range scorecard.Checks { - key := removeInvalidCharFromProperty(check.Check) - checksMap[key] = check.Score - checkKeysList = append(checkKeysList, key) - } - sort.Strings(checkKeysList) - for _, k := range checkKeysList { - checkValuesList = append(checkValuesList, checksMap[k]) - } - values[checkKeys] = checkKeysList - values[checkValues] = checkValuesList - - // TODO(mihaimaruseac): Should we put origin/collector on the edge instead? - values["origin"] = scorecard.Origin - values["collector"] = scorecard.Collector - - result, err := session.WriteTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - query := ` -MATCH (root:Src) -[:SrcHasType]-> (type:SrcType) -[:SrcHasNamespace]-> (ns:SrcNamespace) -[:SrcHasName] -> (name:SrcName) -WHERE type.type = $sourceType AND ns.namespace = $namespace AND name.name = $name AND name.commit = $commit AND name.tag = $tag -MERGE (name) <-[:subject]- (certifyScorecard:CertifyScorecard{timeScanned:$timeScanned,aggregateScore:$aggregateScore,scorecardVersion:$scorecardVersion,scorecardCommit:$scorecardCommit,checkKeys:$checkKeys,checkValues:$checkValues,origin:$origin,collector:$collector}) -RETURN type.type, ns.namespace, name.name, name.commit, name.tag, certifyScorecard` - result, err := tx.Run(query, values) - if err != nil { - return nil, err - } - - // query returns a single record - record, err := result.Single() - if err != nil { - return nil, err - } - - // TODO(mihaimaruseac): Profile to compare returning node vs returning list of properties - certifyScorecardNode := record.Values[5].(dbtype.Node) - checks, err := getCollectedChecks( - certifyScorecardNode.Props[checkKeys].([]interface{}), - certifyScorecardNode.Props[checkValues].([]interface{})) - if err != nil { - return nil, err - } - - scorecard := model.Scorecard{ - TimeScanned: certifyScorecardNode.Props[timeScanned].(time.Time), - AggregateScore: certifyScorecardNode.Props[aggregateScore].(float64), - Checks: checks, - ScorecardVersion: certifyScorecardNode.Props[scorecardVersion].(string), - ScorecardCommit: certifyScorecardNode.Props[scorecardCommit].(string), - Origin: certifyScorecardNode.Props[origin].(string), - Collector: certifyScorecardNode.Props[collector].(string), - } - - tag := record.Values[4] - commit := record.Values[3] - nameStr := record.Values[2].(string) - namespaceStr := record.Values[1].(string) - srcType := record.Values[0].(string) - - src := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - certification := model.CertifyScorecard{ - Source: src, - Scorecard: &scorecard, - } - - return &certification, nil - }) - if err != nil { - return "", err - } - - return result.(*model.CertifyScorecard).ID, nil -} diff --git a/pkg/assembler/backends/neo4j/certifyVEXStatement.go b/pkg/assembler/backends/neo4j/certifyVEXStatement.go deleted file mode 100644 index 76af6e88a4..0000000000 --- a/pkg/assembler/backends/neo4j/certifyVEXStatement.go +++ /dev/null @@ -1,653 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" -) - -func (c *neo4jClient) CertifyVEXStatementList(ctx context.Context, certifyVEXStatementSpec model.CertifyVEXStatementSpec, after *string, first *int) (*model.VEXConnection, error) { - return nil, fmt.Errorf("not implemented: BuildersList") -} - -// TODO (pxp928): fix for new vulnerability -func (c *neo4jClient) CertifyVEXStatement(ctx context.Context, certifyVEXStatementSpec *model.CertifyVEXStatementSpec) ([]*model.CertifyVEXStatement, error) { - - // // TODO: Fix validation - // querySubjectAll := true - // // querySubjectAll, err := helper.ValidatePackageOrArtifactQueryInput(certifyVEXStatementSpec.Subject) - // // if err != nil { - // // return nil, err - // // } - - // // TODO: Fix validation - // queryVulnAll := true - // // queryVulnAll, err := helper.ValidateCveOrGhsaQueryInput(certifyVEXStatementSpec.Vulnerability) - // // if err != nil { - // // return nil, err - // // } - - // queryAll := false - // if querySubjectAll && queryVulnAll { - // queryAll = true - // } - - // session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - // defer session.Close() - - // aggregateCertifyVEXStatement := []*model.CertifyVEXStatement{} - - // if queryAll || (querySubjectAll && certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Cve != nil) || - // (queryVulnAll && certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Package != nil) || - // (certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Package != nil && - // certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Cve != nil) { - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query CVE - // returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - // "version.qualifier_list, certifyVEXStatement, cveYear.year, cveID.id" - - // // query with pkgVersion - // query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - // "-[:subject]-(certifyVEXStatement:CertifyVEXStatement)-[:about]-(cveID:CveID)<-[:CveHasID]" + - // "-(cveYear:CveYear)<-[:CveIsYear]-(rootCve:Cve)" - // sb.WriteString(query) - - // if certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Package != nil { - // setPkgMatchValues(&sb, certifyVEXStatementSpec.Subject.Package, false, &firstMatch, queryValues) - // } - // if certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Cve != nil { - // setCveMatchValues(&sb, certifyVEXStatementSpec.Vulnerability.Cve, &firstMatch, queryValues) - // } - // setCertifyVEXStatementValues(&sb, certifyVEXStatementSpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedCertifyVEXStatement := []*model.CertifyVEXStatement{} - - // for result.Next() { - - // pkgQualifiers := result.Record().Values[5] - // subPath := result.Record().Values[4] - // version := result.Record().Values[3] - // nameString := result.Record().Values[2].(string) - // namespaceString := result.Record().Values[1].(string) - // typeString := result.Record().Values[0].(string) - - // pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // idStr := result.Record().Values[8].(string) - // yearStr := result.Record().Values[7].(int) - // cve := generateModelCve(yearStr, idStr) - - // certifyVEXStatementNode := dbtype.Node{} - // if result.Record().Values[1] != nil { - // certifyVEXStatementNode = result.Record().Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVEXStatement Node not found in neo4j") - // } - - // certifyVEXStatement, err := generateModelCertifyVEXStatement(pkg, cve, certifyVEXStatementNode.Props[status].(string), - // certifyVEXStatementNode.Props[statement].(string), certifyVEXStatementNode.Props[statusNotes].(string), - // certifyVEXStatementNode.Props[justification].(string), certifyVEXStatementNode.Props[origin].(string), - // certifyVEXStatementNode.Props[collector].(string), certifyVEXStatementNode.Props[knownSince].(time.Time)) - - // if err != nil { - // return nil, gqlerror.Errorf("generateModelCertifyVEXStatement failed due to error: %v", err) - // } - - // collectedCertifyVEXStatement = append(collectedCertifyVEXStatement, certifyVEXStatement) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedCertifyVEXStatement, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateCertifyVEXStatement = append(aggregateCertifyVEXStatement, result.([]*model.CertifyVEXStatement)...) - // } - - // if queryAll || (querySubjectAll && certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Ghsa != nil) || - // (queryVulnAll && certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Package != nil) || - // (certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Package != nil && - // certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Ghsa != nil) { - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query ghsa - // returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - // "version.qualifier_list, certifyVEXStatement, ghsaID.id" - - // // query with pkgVersion - // query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - // "-[:subject]-(certifyVEXStatement:CertifyVEXStatement)-[:about]-(ghsaID:GhsaID)<-[:GhsaHasID]" + - // "-(rootGhsa:Ghsa)" - // sb.WriteString(query) - - // if certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Package != nil { - // setPkgMatchValues(&sb, certifyVEXStatementSpec.Subject.Package, false, &firstMatch, queryValues) - // } - // if certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Ghsa != nil { - // setGhsaMatchValues(&sb, certifyVEXStatementSpec.Vulnerability.Ghsa, &firstMatch, queryValues) - // } - // setCertifyVEXStatementValues(&sb, certifyVEXStatementSpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedCertifyVEXStatement := []*model.CertifyVEXStatement{} - - // for result.Next() { - // pkgQualifiers := result.Record().Values[5] - // subPath := result.Record().Values[4] - // version := result.Record().Values[3] - // nameString := result.Record().Values[2].(string) - // namespaceString := result.Record().Values[1].(string) - // typeString := result.Record().Values[0].(string) - - // pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // idStr := result.Record().Values[7].(string) - // ghsa := generateModelGhsa(idStr) - - // certifyVEXStatementNode := dbtype.Node{} - // if result.Record().Values[1] != nil { - // certifyVEXStatementNode = result.Record().Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVEXStatement Node not found in neo4j") - // } - - // certifyVEXStatement, err := generateModelCertifyVEXStatement(pkg, ghsa, certifyVEXStatementNode.Props[status].(string), - // certifyVEXStatementNode.Props[statement].(string), certifyVEXStatementNode.Props[statusNotes].(string), - // certifyVEXStatementNode.Props[justification].(string), certifyVEXStatementNode.Props[origin].(string), - // certifyVEXStatementNode.Props[collector].(string), certifyVEXStatementNode.Props[knownSince].(time.Time)) - - // if err != nil { - // return nil, gqlerror.Errorf("generateModelCertifyVEXStatement failed due to error: %v", err) - // } - - // collectedCertifyVEXStatement = append(collectedCertifyVEXStatement, certifyVEXStatement) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedCertifyVEXStatement, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateCertifyVEXStatement = append(aggregateCertifyVEXStatement, result.([]*model.CertifyVEXStatement)...) - // } - - // if queryAll || (querySubjectAll && certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Osv != nil) || - // (queryVulnAll && certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Package != nil) || - // (certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Package != nil && - // certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Osv != nil) { - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query ghsa - // returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - // "version.qualifier_list, certifyVuln, osvID.id" - - // // query with pkgVersion - // query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - // "-[:subject]-(certifyVEXStatement:CertifyVEXStatement)-[:about]-(osvID:OsvID)<-[:OsvHasID]" + - // "-(rootOsv:Osv)" - // sb.WriteString(query) - - // if certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Package != nil { - // setPkgMatchValues(&sb, certifyVEXStatementSpec.Subject.Package, false, &firstMatch, queryValues) - // } - // if certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Osv != nil { - // setOSVMatchValues(&sb, certifyVEXStatementSpec.Vulnerability.Osv, &firstMatch, queryValues) - // } - // setCertifyVEXStatementValues(&sb, certifyVEXStatementSpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedCertifyVEXStatement := []*model.CertifyVEXStatement{} - - // for result.Next() { - // pkgQualifiers := result.Record().Values[5] - // subPath := result.Record().Values[4] - // version := result.Record().Values[3] - // nameString := result.Record().Values[2].(string) - // namespaceString := result.Record().Values[1].(string) - // typeString := result.Record().Values[0].(string) - - // pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // id := result.Record().Values[7].(string) - // osv := generateModelOsv(id) - - // certifyVEXStatementNode := dbtype.Node{} - // if result.Record().Values[1] != nil { - // certifyVEXStatementNode = result.Record().Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVEXStatement Node not found in neo4j") - // } - - // certifyVEXStatement, err := generateModelCertifyVEXStatement(pkg, osv, certifyVEXStatementNode.Props[status].(string), - // certifyVEXStatementNode.Props[statement].(string), certifyVEXStatementNode.Props[statusNotes].(string), - // certifyVEXStatementNode.Props[justification].(string), certifyVEXStatementNode.Props[origin].(string), - // certifyVEXStatementNode.Props[collector].(string), certifyVEXStatementNode.Props[knownSince].(time.Time)) - - // if err != nil { - // return nil, gqlerror.Errorf("generateModelCertifyVEXStatement failed due to error: %v", err) - // } - - // collectedCertifyVEXStatement = append(collectedCertifyVEXStatement, certifyVEXStatement) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedCertifyVEXStatement, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateCertifyVEXStatement = append(aggregateCertifyVEXStatement, result.([]*model.CertifyVEXStatement)...) - // } - - // if queryAll || (querySubjectAll && certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Cve != nil) || - // (queryVulnAll && certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Artifact != nil) || - // (certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Artifact != nil && - // certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Cve != nil) { - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query CVE - // returnValue := " RETURN a.algorithm, a.digest, certifyVEXStatement, cveYear.year, cveID.id" - - // // query artifact - // query := "MATCH (a:Artifact)" + - // "-[:subject]-(certifyVEXStatement:CertifyVEXStatement)-[:about]-(cveID:CveID)<-[:CveHasID]" + - // "-(cveYear:CveYear)<-[:CveIsYear]-(rootCve:Cve)" - // sb.WriteString(query) - - // if certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Artifact != nil { - // setArtifactMatchValues(&sb, certifyVEXStatementSpec.Subject.Artifact, false, &firstMatch, queryValues) - // } - // if certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Cve != nil { - // setCveMatchValues(&sb, certifyVEXStatementSpec.Vulnerability.Cve, &firstMatch, queryValues) - // } - // setCertifyVEXStatementValues(&sb, certifyVEXStatementSpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedCertifyVEXStatement := []*model.CertifyVEXStatement{} - - // for result.Next() { - // algorithm := result.Record().Values[0].(string) - // digest := result.Record().Values[1].(string) - // artifact := generateModelArtifact(algorithm, digest) - - // idStr := result.Record().Values[4].(string) - // yearStr := result.Record().Values[3].(int) - // cve := generateModelCve(yearStr, idStr) - - // certifyVEXStatementNode := dbtype.Node{} - // if result.Record().Values[1] != nil { - // certifyVEXStatementNode = result.Record().Values[2].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVEXStatement Node not found in neo4j") - // } - - // certifyVEXStatement, err := generateModelCertifyVEXStatement(artifact, cve, certifyVEXStatementNode.Props[status].(string), - // certifyVEXStatementNode.Props[statement].(string), certifyVEXStatementNode.Props[statusNotes].(string), - // certifyVEXStatementNode.Props[justification].(string), certifyVEXStatementNode.Props[origin].(string), - // certifyVEXStatementNode.Props[collector].(string), certifyVEXStatementNode.Props[knownSince].(time.Time)) - - // if err != nil { - // return nil, gqlerror.Errorf("generateModelCertifyVEXStatement failed due to error: %v", err) - // } - - // collectedCertifyVEXStatement = append(collectedCertifyVEXStatement, certifyVEXStatement) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedCertifyVEXStatement, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateCertifyVEXStatement = append(aggregateCertifyVEXStatement, result.([]*model.CertifyVEXStatement)...) - // } - - // if queryAll || (querySubjectAll && certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Ghsa != nil) || - // (queryVulnAll && certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Artifact != nil) || - // (certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Artifact != nil && - // certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Ghsa != nil) { - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query ghsa - // returnValue := " RETURN a.algorithm, a.digest, certifyVEXStatement, ghsaID.id" - - // // query artifact - // query := "MATCH (a:Artifact)" + - // "-[:subject]-(certifyVEXStatement:CertifyVEXStatement)-[:about]-(ghsaID:GhsaID)<-[:GhsaHasID]" + - // "-(rootGhsa:Ghsa)" - // sb.WriteString(query) - - // if certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Artifact != nil { - // setArtifactMatchValues(&sb, certifyVEXStatementSpec.Subject.Artifact, false, &firstMatch, queryValues) - // } - // if certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Ghsa != nil { - // setGhsaMatchValues(&sb, certifyVEXStatementSpec.Vulnerability.Ghsa, &firstMatch, queryValues) - // } - // setCertifyVEXStatementValues(&sb, certifyVEXStatementSpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedCertifyVEXStatement := []*model.CertifyVEXStatement{} - - // for result.Next() { - // algorithm := result.Record().Values[0].(string) - // digest := result.Record().Values[1].(string) - // artifact := generateModelArtifact(algorithm, digest) - - // idStr := result.Record().Values[3].(string) - // ghsa := generateModelGhsa(idStr) - - // certifyVEXStatementNode := dbtype.Node{} - // if result.Record().Values[1] != nil { - // certifyVEXStatementNode = result.Record().Values[2].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVEXStatement Node not found in neo4j") - // } - - // certifyVEXStatement, err := generateModelCertifyVEXStatement(artifact, ghsa, certifyVEXStatementNode.Props[status].(string), - // certifyVEXStatementNode.Props[statement].(string), certifyVEXStatementNode.Props[statusNotes].(string), - // certifyVEXStatementNode.Props[justification].(string), certifyVEXStatementNode.Props[origin].(string), - // certifyVEXStatementNode.Props[collector].(string), certifyVEXStatementNode.Props[knownSince].(time.Time)) - - // if err != nil { - // return nil, gqlerror.Errorf("generateModelCertifyVEXStatement failed due to error: %v", err) - // } - // collectedCertifyVEXStatement = append(collectedCertifyVEXStatement, certifyVEXStatement) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedCertifyVEXStatement, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateCertifyVEXStatement = append(aggregateCertifyVEXStatement, result.([]*model.CertifyVEXStatement)...) - // } - - // if queryAll || (querySubjectAll && certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Osv != nil) || - // (queryVulnAll && certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Artifact != nil) || - // (certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Artifact != nil && - // certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Osv != nil) { - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query ghsa - // returnValue := " RETURN a.algorithm, a.digest, certifyVEXStatement, osvID.id" - - // // query artifact - // query := "MATCH (a:Artifact)" + - // "-[:subject]-(certifyVEXStatement:CertifyVEXStatement)-[:about]-(osvID:OsvID)<-[:OsvHasID]" + - // "-(rootOsv:Osv)" - // sb.WriteString(query) - - // if certifyVEXStatementSpec.Subject != nil && certifyVEXStatementSpec.Subject.Artifact != nil { - // setArtifactMatchValues(&sb, certifyVEXStatementSpec.Subject.Artifact, false, &firstMatch, queryValues) - // } - // if certifyVEXStatementSpec.Vulnerability != nil && certifyVEXStatementSpec.Vulnerability.Osv != nil { - // setOSVMatchValues(&sb, certifyVEXStatementSpec.Vulnerability.Osv, &firstMatch, queryValues) - // } - // setCertifyVEXStatementValues(&sb, certifyVEXStatementSpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedCertifyVEXStatement := []*model.CertifyVEXStatement{} - - // for result.Next() { - // algorithm := result.Record().Values[0].(string) - // digest := result.Record().Values[1].(string) - // artifact := generateModelArtifact(algorithm, digest) - - // id := result.Record().Values[7].(string) - // osv := generateModelOsv(id) - - // certifyVEXStatementNode := dbtype.Node{} - // if result.Record().Values[1] != nil { - // certifyVEXStatementNode = result.Record().Values[2].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVEXStatement Node not found in neo4j") - // } - - // certifyVEXStatement, err := generateModelCertifyVEXStatement(artifact, osv, certifyVEXStatementNode.Props[status].(string), - // certifyVEXStatementNode.Props[statement].(string), certifyVEXStatementNode.Props[statusNotes].(string), - // certifyVEXStatementNode.Props[justification].(string), certifyVEXStatementNode.Props[origin].(string), - // certifyVEXStatementNode.Props[collector].(string), certifyVEXStatementNode.Props[knownSince].(time.Time)) - - // if err != nil { - // return nil, gqlerror.Errorf("generateModelCertifyVEXStatement failed due to error: %v", err) - // } - - // collectedCertifyVEXStatement = append(collectedCertifyVEXStatement, certifyVEXStatement) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedCertifyVEXStatement, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateCertifyVEXStatement = append(aggregateCertifyVEXStatement, result.([]*model.CertifyVEXStatement)...) - // } - - // return aggregateCertifyVEXStatement, nil - return []*model.CertifyVEXStatement{}, fmt.Errorf("not implemented - CertifyVEXStatement") -} - -// func setCertifyVEXStatementValues(sb *strings.Builder, certifyVEXStatementSpec *model.CertifyVEXStatementSpec, firstMatch *bool, queryValues map[string]any) { -// if certifyVEXStatementSpec.KnownSince != nil { -// matchProperties(sb, *firstMatch, "certifyVEXStatement", knownSince, "$"+knownSince) -// *firstMatch = false -// queryValues[knownSince] = certifyVEXStatementSpec.KnownSince.UTC() -// } -// if certifyVEXStatementSpec.Status != nil { -// matchProperties(sb, *firstMatch, "certifyVEXStatement", status, "$"+status) -// *firstMatch = false -// queryValues["status"] = certifyVEXStatementSpec.Status.String() -// } -// if certifyVEXStatementSpec.Statement != nil { -// matchProperties(sb, *firstMatch, "certifyVEXStatement", statement, "$"+statement) -// *firstMatch = false -// queryValues["statement"] = certifyVEXStatementSpec.Statement -// } -// if certifyVEXStatementSpec.StatusNotes != nil { -// matchProperties(sb, *firstMatch, "certifyVEXStatement", statusNotes, "$"+statusNotes) -// *firstMatch = false -// queryValues["statusNotes"] = certifyVEXStatementSpec.StatusNotes -// } -// if certifyVEXStatementSpec.VexJustification != nil { -// matchProperties(sb, *firstMatch, "certifyVEXStatement", justification, "$"+justification) -// *firstMatch = false -// queryValues["justification"] = certifyVEXStatementSpec.VexJustification.String() -// } -// if certifyVEXStatementSpec.Origin != nil { -// matchProperties(sb, *firstMatch, "certifyVEXStatement", origin, "$"+origin) -// *firstMatch = false -// queryValues[origin] = certifyVEXStatementSpec.Origin -// } -// if certifyVEXStatementSpec.Collector != nil { -// matchProperties(sb, *firstMatch, "certifyVEXStatement", collector, "$"+collector) -// *firstMatch = false -// queryValues[collector] = certifyVEXStatementSpec.Collector -// } -// } - -// func generateModelCertifyVEXStatement(subject model.PackageOrArtifact, vuln model.Vulnerability, status, statement, statusNotes, justification, origin, collector string, knownSince time.Time) (*model.CertifyVEXStatement, error) { -// vexStatus, err := convertStatusToEnum(status) -// if err != nil { -// return nil, fmt.Errorf("convertStatusToEnum failed with error: %w", err) -// } - -// vexJustification, err := convertJustificationToEnum(justification) -// if err != nil { -// return nil, fmt.Errorf("convertJustificationToEnum failed with error: %w", err) -// } - -// certifyVEXStatement := model.CertifyVEXStatement{ -// Subject: subject, -// Vulnerability: vuln, -// Status: vexStatus, -// VexJustification: vexJustification, -// Statement: statement, -// StatusNotes: statusNotes, -// KnownSince: knownSince, -// Origin: origin, -// Collector: collector, -// } -// return &certifyVEXStatement, nil -// } - -// func convertStatusToEnum(status string) (model.VexStatus, error) { -// if status == model.VexStatusNotAffected.String() { -// return model.VexStatusAffected, nil -// } -// if status == model.VexStatusAffected.String() { -// return model.VexStatusAffected, nil -// } -// if status == model.VexStatusFixed.String() { -// return model.VexStatusFixed, nil -// } -// if status == model.VexStatusUnderInvestigation.String() { -// return model.VexStatusUnderInvestigation, nil -// } -// return model.VexStatusAffected, fmt.Errorf("failed to convert status to enum") -// } - -// func convertJustificationToEnum(justification string) (model.VexJustification, error) { -// if justification == model.VexJustificationNotProvided.String() { -// return model.VexJustificationNotProvided, nil -// } -// if justification == model.VexJustificationComponentNotPresent.String() { -// return model.VexJustificationComponentNotPresent, nil -// } -// if justification == model.VexJustificationVulnerableCodeNotPresent.String() { -// return model.VexJustificationVulnerableCodeNotPresent, nil -// } -// if justification == model.VexJustificationVulnerableCodeNotInExecutePath.String() { -// return model.VexJustificationVulnerableCodeNotInExecutePath, nil -// } -// if justification == model.VexJustificationVulnerableCodeCannotBeControlledByAdversary.String() { -// return model.VexJustificationVulnerableCodeCannotBeControlledByAdversary, nil -// } -// if justification == model.VexJustificationInlineMitigationsAlreadyExist.String() { -// return model.VexJustificationInlineMitigationsAlreadyExist, nil -// } -// if justification == model.VexJustificationNotProvided.String() { -// return model.VexJustificationNotProvided, nil -// } -// return model.VexJustificationNotProvided, fmt.Errorf("failed to convert justification to enum") -// } - -func (c *neo4jClient) IngestVEXStatement(ctx context.Context, subject model.PackageOrArtifactInput, vulnerability model.IDorVulnerabilityInput, vexStatement model.VexStatementInputSpec) (string, error) { - - // err := helper.ValidatePackageOrArtifactInput(&subject, "IngestVEXStatement") - // if err != nil { - // return nil, err - // } - // err = helper.ValidateVulnerabilityIngestionInput(vulnerability, "IngestVEXStatement", false) - // if err != nil { - // return nil, err - // } - // panic(fmt.Errorf("not implemented: IngestVEXStatement - IngestVEXStatement")) - return "", fmt.Errorf("not implemented - IngestVEXStatement") -} - -func (c *neo4jClient) IngestVEXStatements(ctx context.Context, subjects model.PackageOrArtifactInputs, vulnerabilities []*model.IDorVulnerabilityInput, vexStatements []*model.VexStatementInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented - IngestVEXStatements") -} diff --git a/pkg/assembler/backends/neo4j/certifyVuln.go b/pkg/assembler/backends/neo4j/certifyVuln.go deleted file mode 100644 index 8cea267557..0000000000 --- a/pkg/assembler/backends/neo4j/certifyVuln.go +++ /dev/null @@ -1,567 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" -) - -const ( - dbUri string = "dbUri" - dbVersion string = "dbVersion" - scannerUri string = "scannerUri" - scannerVersion string = "scannerVersion" -) - -// Query CertifyVuln - -func (c *neo4jClient) CertifyVulnList(ctx context.Context, certifyVulnSpec model.CertifyVulnSpec, after *string, first *int) (*model.CertifyVulnConnection, error) { - return nil, fmt.Errorf("not implemented: CertifyVulnList") -} - -// TODO (pxp928): fix for new vulnerability -func (c *neo4jClient) CertifyVuln(ctx context.Context, certifyVulnSpec *model.CertifyVulnSpec) ([]*model.CertifyVuln, error) { - - // session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - // defer session.Close() - - // // TODO: Fix validation - // queryAll := true - // // queryAll, err := helper.ValidateVulnerabilityQueryInput(certifyVulnSpec.Vulnerability) - // // if err != nil { - // // return nil, err - // // } - - // aggregateCertifyVuln := []*model.CertifyVuln{} - - // if queryAll || (certifyVulnSpec.Vulnerability != nil && certifyVulnSpec.Vulnerability.Cve != nil) { - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query CVE - // returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - // "version.qualifier_list, certifyVuln, cveYear.year, cveID.id" - - // // query with pkgVersion - // query := "MATCH (rootPkg:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - // "-[:subject]-(certifyVuln:CertifyVuln)-[:is_vuln_to]-(cveID:CveID)<-[:CveHasID]" + - // "-(cveYear:CveYear)<-[:CveIsYear]-(rootCve:Cve)" - // sb.WriteString(query) - - // setPkgMatchValues(&sb, certifyVulnSpec.Package, false, &firstMatch, queryValues) - // if certifyVulnSpec.Vulnerability != nil && certifyVulnSpec.Vulnerability.Cve != nil { - // setCveMatchValues(&sb, certifyVulnSpec.Vulnerability.Cve, &firstMatch, queryValues) - // } - // setCertifyVulnValues(&sb, certifyVulnSpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedCertifyVuln := []*model.CertifyVuln{} - - // for result.Next() { - // pkgQualifiers := result.Record().Values[5] - // subPath := result.Record().Values[4] - // version := result.Record().Values[3] - // nameString := result.Record().Values[2].(string) - // namespaceString := result.Record().Values[1].(string) - // typeString := result.Record().Values[0].(string) - - // pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // idStr := result.Record().Values[8].(string) - // yearStr := result.Record().Values[7].(int) - // cve := generateModelCve(yearStr, idStr) - - // certifyVulnNode := dbtype.Node{} - // if result.Record().Values[1] != nil { - // certifyVulnNode = result.Record().Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVuln Node not found in neo4j") - // } - - // certifyVuln := generateModelCertifyVuln(pkg, cve, certifyVulnNode.Props[timeScanned].(time.Time), certifyVulnNode.Props[dbUri].(string), - // certifyVulnNode.Props[dbVersion].(string), certifyVulnNode.Props[scannerUri].(string), certifyVulnNode.Props[scannerVersion].(string), - // certifyVulnNode.Props[origin].(string), certifyVulnNode.Props[collector].(string)) - - // collectedCertifyVuln = append(collectedCertifyVuln, certifyVuln) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedCertifyVuln, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateCertifyVuln = append(aggregateCertifyVuln, result.([]*model.CertifyVuln)...) - // } - - // if queryAll || (certifyVulnSpec.Vulnerability != nil && certifyVulnSpec.Vulnerability.Ghsa != nil) { - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query ghsa - // returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - // "version.qualifier_list, certifyVuln, ghsaID.id" - - // // query with pkgVersion - // query := "MATCH (rootPkg:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - // "-[:subject]-(certifyVuln:CertifyVuln)-[:is_vuln_to]-(ghsaID:GhsaID)<-[:GhsaHasID]" + - // "-(rootGhsa:Ghsa)" - // sb.WriteString(query) - - // setPkgMatchValues(&sb, certifyVulnSpec.Package, false, &firstMatch, queryValues) - // if certifyVulnSpec.Vulnerability != nil && certifyVulnSpec.Vulnerability.Ghsa != nil { - // setGhsaMatchValues(&sb, certifyVulnSpec.Vulnerability.Ghsa, &firstMatch, queryValues) - // } - // setCertifyVulnValues(&sb, certifyVulnSpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedCertifyVuln := []*model.CertifyVuln{} - - // for result.Next() { - // pkgQualifiers := result.Record().Values[5] - // subPath := result.Record().Values[4] - // version := result.Record().Values[3] - // nameString := result.Record().Values[2].(string) - // namespaceString := result.Record().Values[1].(string) - // typeString := result.Record().Values[0].(string) - - // pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // idStr := result.Record().Values[7].(string) - // ghsa := generateModelGhsa(idStr) - - // certifyVulnNode := dbtype.Node{} - // if result.Record().Values[1] != nil { - // certifyVulnNode = result.Record().Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVuln Node not found in neo4j") - // } - - // certifyVuln := generateModelCertifyVuln(pkg, ghsa, certifyVulnNode.Props[timeScanned].(time.Time), certifyVulnNode.Props[dbUri].(string), - // certifyVulnNode.Props[dbVersion].(string), certifyVulnNode.Props[scannerUri].(string), certifyVulnNode.Props[scannerVersion].(string), - // certifyVulnNode.Props[origin].(string), certifyVulnNode.Props[collector].(string)) - - // collectedCertifyVuln = append(collectedCertifyVuln, certifyVuln) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedCertifyVuln, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateCertifyVuln = append(aggregateCertifyVuln, result.([]*model.CertifyVuln)...) - // } - - // if queryAll || (certifyVulnSpec.Vulnerability != nil && certifyVulnSpec.Vulnerability.Osv != nil) { - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query ghsa - // returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - // "version.qualifier_list, certifyVuln, osvID.id" - - // // query with pkgVersion - // //(root:Osv)-[:OsvHasID]->(osvID:OsvID) - // query := "MATCH (rootPkg:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - // "-[:subject]-(certifyVuln:CertifyVuln)-[:is_vuln_to]-(osvID:OsvID)<-[:OsvHasID]" + - // "-(rootOsv:Osv)" - // sb.WriteString(query) - - // setPkgMatchValues(&sb, certifyVulnSpec.Package, false, &firstMatch, queryValues) - // if certifyVulnSpec.Vulnerability != nil && certifyVulnSpec.Vulnerability.Osv != nil { - // setOSVMatchValues(&sb, certifyVulnSpec.Vulnerability.Osv, &firstMatch, queryValues) - // } - // setCertifyVulnValues(&sb, certifyVulnSpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedCertifyVuln := []*model.CertifyVuln{} - - // for result.Next() { - // pkgQualifiers := result.Record().Values[5] - // subPath := result.Record().Values[4] - // version := result.Record().Values[3] - // nameString := result.Record().Values[2].(string) - // namespaceString := result.Record().Values[1].(string) - // typeString := result.Record().Values[0].(string) - - // pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // id := result.Record().Values[7].(string) - // osv := generateModelOsv(id) - - // certifyVulnNode := dbtype.Node{} - // if result.Record().Values[1] != nil { - // certifyVulnNode = result.Record().Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVuln Node not found in neo4j") - // } - - // certifyVuln := generateModelCertifyVuln(pkg, osv, certifyVulnNode.Props[timeScanned].(time.Time), certifyVulnNode.Props[dbUri].(string), - // certifyVulnNode.Props[dbVersion].(string), certifyVulnNode.Props[scannerUri].(string), certifyVulnNode.Props[scannerVersion].(string), - // certifyVulnNode.Props[origin].(string), certifyVulnNode.Props[collector].(string)) - - // collectedCertifyVuln = append(collectedCertifyVuln, certifyVuln) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedCertifyVuln, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateCertifyVuln = append(aggregateCertifyVuln, result.([]*model.CertifyVuln)...) - // } - // return aggregateCertifyVuln, nil - return []*model.CertifyVuln{}, fmt.Errorf("not implemented - CertifyVuln") -} - -// func setCertifyVulnValues(sb *strings.Builder, certifyVulnSpec *model.CertifyVulnSpec, firstMatch *bool, queryValues map[string]any) { -// if certifyVulnSpec.TimeScanned != nil { -// matchProperties(sb, *firstMatch, "certifyVuln", timeScanned, "$"+timeScanned) -// *firstMatch = false -// queryValues[timeScanned] = certifyVulnSpec.TimeScanned.UTC() -// } -// if certifyVulnSpec.DbURI != nil { -// matchProperties(sb, *firstMatch, "certifyVuln", dbUri, "$"+dbUri) -// *firstMatch = false -// queryValues[dbUri] = certifyVulnSpec.DbURI -// } -// if certifyVulnSpec.DbVersion != nil { -// matchProperties(sb, *firstMatch, "certifyVuln", dbVersion, "$"+dbVersion) -// *firstMatch = false -// queryValues[dbVersion] = certifyVulnSpec.DbVersion -// } -// if certifyVulnSpec.ScannerURI != nil { -// matchProperties(sb, *firstMatch, "certifyVuln", scannerUri, "$"+scannerUri) -// *firstMatch = false -// queryValues[scannerUri] = certifyVulnSpec.ScannerURI -// } -// if certifyVulnSpec.ScannerVersion != nil { -// matchProperties(sb, *firstMatch, "certifyVuln", scannerVersion, "$"+scannerVersion) -// *firstMatch = false -// queryValues[scannerVersion] = certifyVulnSpec.ScannerVersion -// } -// if certifyVulnSpec.Origin != nil { -// matchProperties(sb, *firstMatch, "certifyVuln", origin, "$"+origin) -// *firstMatch = false -// queryValues[origin] = certifyVulnSpec.Origin -// } -// if certifyVulnSpec.Collector != nil { -// matchProperties(sb, *firstMatch, "certifyVuln", collector, "$"+collector) -// *firstMatch = false -// queryValues[collector] = certifyVulnSpec.Collector -// } -// } - -// func generateModelCertifyVuln(pkg *model.Package, vuln model.Vulnerability, timeScanned time.Time, dbUri, dbVersion, scannerUri, -// scannerVersion, origin, collector string) *model.CertifyVuln { - -// metadata := &model.VulnerabilityMetaData{ -// TimeScanned: timeScanned, -// DbURI: dbUri, -// DbVersion: dbVersion, -// ScannerURI: scannerUri, -// ScannerVersion: scannerVersion, -// Origin: origin, -// Collector: collector, -// } - -// certifyVuln := model.CertifyVuln{ -// Package: pkg, -// Vulnerability: vuln, -// Metadata: metadata, -// } -// return &certifyVuln -// } - -// Ingest Vulnerability - -func (c *neo4jClient) IngestCertifyVuln(ctx context.Context, pkg model.IDorPkgInput, vulnerability model.IDorVulnerabilityInput, certifyVuln model.ScanMetadataInput) (string, error) { - - // err := helper.ValidateVulnerabilityIngestionInput(vulnerability, "IngestVulnerability", true) - // if err != nil { - // return nil, err - // } - - // session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) - // defer session.Close() - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // queryValues[timeScanned] = certifyVuln.TimeScanned.UTC() - // queryValues[dbUri] = certifyVuln.DbURI - // queryValues[dbVersion] = certifyVuln.DbVersion - // queryValues[scannerUri] = certifyVuln.ScannerURI - // queryValues[scannerVersion] = certifyVuln.ScannerVersion - // queryValues[origin] = certifyVuln.Origin - // queryValues[collector] = certifyVuln.Collector - - // // TODO: use generics here between PkgInputSpec and PkgSpecs? - // selectedPkgSpec := helper.ConvertPkgInputSpecToPkgSpec(&pkg) - - // if vulnerability.Osv != nil { - // selectedOsvSepc := helper.ConvertOsvInputSpecToOsvSpec(vulnerability.Osv) - - // returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - // "version.qualifier_list, certifyVuln, osvID.id" - - // query := "MATCH (rootPkg:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" - - // sb.WriteString(query) - // setPkgMatchValues(&sb, selectedPkgSpec, false, &firstMatch, queryValues) - - // query = "\nMATCH (rootOsv:Osv)-[:OsvHasID]->(osvID:OsvID)" - // sb.WriteString(query) - // firstMatch = true - // setOSVMatchValues(&sb, selectedOsvSepc, &firstMatch, queryValues) - - // merge := "\nMERGE (version)<-[:subject]-(certifyVuln:CertifyVuln{timeScanned:$timeScanned,dbUri:$dbUri," + - // "dbVersion:$dbVersion,scannerUri:$scannerUri,scannerVersion:$scannerVersion,origin:$origin,collector:$collector})" + - // "-[:is_vuln_to]->(osvID)" - // sb.WriteString(merge) - // sb.WriteString(returnValue) - - // result, err := session.WriteTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // // query returns a single record - // record, err := result.Single() - // if err != nil { - // return nil, err - // } - - // pkgQualifiers := record.Values[5] - // subPath := record.Values[4] - // version := record.Values[3] - // nameString := record.Values[2].(string) - // namespaceString := record.Values[1].(string) - // typeString := record.Values[0].(string) - - // pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // id := record.Values[7].(string) - // osv := generateModelOsv(id) - - // certifyVulnNode := dbtype.Node{} - // if record.Values[1] != nil { - // certifyVulnNode = record.Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVuln Node not found in neo4j") - // } - - // certifyVuln := generateModelCertifyVuln(pkg, osv, certifyVulnNode.Props[timeScanned].(time.Time), certifyVulnNode.Props[dbUri].(string), - // certifyVulnNode.Props[dbVersion].(string), certifyVulnNode.Props[scannerUri].(string), certifyVulnNode.Props[scannerVersion].(string), - // certifyVulnNode.Props[origin].(string), certifyVulnNode.Props[collector].(string)) - - // return certifyVuln, nil - // }) - // if err != nil { - // return nil, err - // } - - // return result.(*model.CertifyVuln), nil - // } else if vulnerability.Cve != nil { - // selectedCveSepc := helper.ConvertCveInputSpecToCveSpec(vulnerability.Cve) - - // returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - // "version.qualifier_list, certifyVuln, cveYear.year, cveID.id" - - // query := "MATCH (rootPkg:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" - - // sb.WriteString(query) - // setPkgMatchValues(&sb, selectedPkgSpec, false, &firstMatch, queryValues) - - // query = "\nMATCH (rootCve:Cve)-[:CveIsYear]->(cveYear:CveYear)-[:CveHasID]->(cveID:CveID)" - // sb.WriteString(query) - // firstMatch = true - // setCveMatchValues(&sb, selectedCveSepc, &firstMatch, queryValues) - - // merge := "\nMERGE (version)<-[:subject]-(certifyVuln:CertifyVuln{timeScanned:$timeScanned,dbUri:$dbUri," + - // "dbVersion:$dbVersion,scannerUri:$scannerUri,scannerVersion:$scannerVersion,origin:$origin,collector:$collector})" + - // "-[:is_vuln_to]->(cveID)" - // sb.WriteString(merge) - // sb.WriteString(returnValue) - - // result, err := session.WriteTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // // query returns a single record - // record, err := result.Single() - // if err != nil { - // return nil, err - // } - - // pkgQualifiers := record.Values[5] - // subPath := record.Values[4] - // version := record.Values[3] - // nameString := record.Values[2].(string) - // namespaceString := record.Values[1].(string) - // typeString := record.Values[0].(string) - - // pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // idStr := record.Values[8].(string) - // yearStr := record.Values[7].(int) - // cve := generateModelCve(yearStr, idStr) - - // certifyVulnNode := dbtype.Node{} - // if record.Values[1] != nil { - // certifyVulnNode = record.Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVuln Node not found in neo4j") - // } - - // certifyVuln := generateModelCertifyVuln(pkg, cve, certifyVulnNode.Props[timeScanned].(time.Time), certifyVulnNode.Props[dbUri].(string), - // certifyVulnNode.Props[dbVersion].(string), certifyVulnNode.Props[scannerUri].(string), certifyVulnNode.Props[scannerVersion].(string), - // certifyVulnNode.Props[origin].(string), certifyVulnNode.Props[collector].(string)) - - // return certifyVuln, nil - // }) - // if err != nil { - // return nil, err - // } - - // return result.(*model.CertifyVuln), nil - // } else if vulnerability.Ghsa != nil { - // selectedGhsaSepc := helper.ConvertGhsaInputSpecToGhsaSpec(vulnerability.Ghsa) - - // returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - // "version.qualifier_list, certifyVuln, ghsaID.id" - - // query := "MATCH (rootPkg:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" - - // sb.WriteString(query) - // setPkgMatchValues(&sb, selectedPkgSpec, false, &firstMatch, queryValues) - - // query = "\nMATCH (rootGhsa:Ghsa)-[:GhsaHasID]->(ghsaID:GhsaID)" - // sb.WriteString(query) - // firstMatch = true - // setGhsaMatchValues(&sb, selectedGhsaSepc, &firstMatch, queryValues) - - // merge := "\nMERGE (version)<-[:subject]-(certifyVuln:CertifyVuln{timeScanned:$timeScanned,dbUri:$dbUri," + - // "dbVersion:$dbVersion,scannerUri:$scannerUri,scannerVersion:$scannerVersion,origin:$origin,collector:$collector})" + - // "-[:is_vuln_to]->(ghsaID)" - // sb.WriteString(merge) - // sb.WriteString(returnValue) - - // result, err := session.WriteTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // // query returns a single record - // record, err := result.Single() - // if err != nil { - // return nil, err - // } - - // pkgQualifiers := record.Values[5] - // subPath := record.Values[4] - // version := record.Values[3] - // nameString := record.Values[2].(string) - // namespaceString := record.Values[1].(string) - // typeString := record.Values[0].(string) - - // pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // idStr := record.Values[7].(string) - // ghsa := generateModelGhsa(idStr) - - // certifyVulnNode := dbtype.Node{} - // if record.Values[1] != nil { - // certifyVulnNode = record.Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("certifyVuln Node not found in neo4j") - // } - - // certifyVuln := generateModelCertifyVuln(pkg, ghsa, certifyVulnNode.Props[timeScanned].(time.Time), certifyVulnNode.Props[dbUri].(string), - // certifyVulnNode.Props[dbVersion].(string), certifyVulnNode.Props[scannerUri].(string), certifyVulnNode.Props[scannerVersion].(string), - // certifyVulnNode.Props[origin].(string), certifyVulnNode.Props[collector].(string)) - - // return certifyVuln, nil - // }) - // if err != nil { - // return nil, err - // } - - // return result.(*model.CertifyVuln), nil - // } else { - // return nil, gqlerror.Errorf("package or source not specified for IngestOccurrence") - // } - return "", fmt.Errorf("not implemented - IngestCertifyVuln") -} - -func (c *neo4jClient) IngestCertifyVulns(ctx context.Context, pkgs []*model.IDorPkgInput, vulnerabilities []*model.IDorVulnerabilityInput, certifyVulns []*model.ScanMetadataInput) ([]string, error) { - return []string{}, fmt.Errorf("not implemented - IngestCertifyVulns") -} diff --git a/pkg/assembler/backends/neo4j/contact.go b/pkg/assembler/backends/neo4j/contact.go deleted file mode 100644 index 560099e7c0..0000000000 --- a/pkg/assembler/backends/neo4j/contact.go +++ /dev/null @@ -1,39 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" -) - -func (c *neo4jClient) PointOfContactList(ctx context.Context, pointOfContactSpec model.PointOfContactSpec, after *string, first *int) (*model.PointOfContactConnection, error) { - return nil, fmt.Errorf("not implemented: PointOfContactList") -} - -func (c *neo4jClient) IngestPointOfContact(ctx context.Context, subject model.PackageSourceOrArtifactInput, pkgMatchType *model.MatchFlags, pointOfContact model.PointOfContactInputSpec) (string, error) { - return "", fmt.Errorf("not implemented: IngestPointOfContact") -} - -func (c *neo4jClient) PointOfContact(ctx context.Context, pointOfContactSpec *model.PointOfContactSpec) ([]*model.PointOfContact, error) { - return nil, fmt.Errorf("not implemented: PointOfContact") -} - -func (c *neo4jClient) IngestPointOfContacts(ctx context.Context, subjects model.PackageSourceOrArtifactInputs, pkgMatchType *model.MatchFlags, pointOfContacts []*model.PointOfContactInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestPointOfContacts") -} diff --git a/pkg/assembler/backends/neo4j/hasMetadata.go b/pkg/assembler/backends/neo4j/hasMetadata.go deleted file mode 100644 index 3e8219a887..0000000000 --- a/pkg/assembler/backends/neo4j/hasMetadata.go +++ /dev/null @@ -1,39 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" -) - -func (c *neo4jClient) HasMetadataList(ctx context.Context, hasMetadataSpec model.HasMetadataSpec, after *string, first *int) (*model.HasMetadataConnection, error) { - return nil, fmt.Errorf("not implemented: HasMetadataList") -} - -func (c *neo4jClient) IngestHasMetadata(ctx context.Context, subject model.PackageSourceOrArtifactInput, pkgMatchType *model.MatchFlags, hasMetadata model.HasMetadataInputSpec) (string, error) { - return "", fmt.Errorf("not implemented: IngestHasMetadata") -} - -func (c *neo4jClient) HasMetadata(ctx context.Context, hasMetadataSpec *model.HasMetadataSpec) ([]*model.HasMetadata, error) { - return nil, fmt.Errorf("not implemented: HasMetadata") -} - -func (c *neo4jClient) IngestBulkHasMetadata(ctx context.Context, subjects model.PackageSourceOrArtifactInputs, pkgMatchType *model.MatchFlags, hasMetadataList []*model.HasMetadataInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestBulkHasMetadata") -} diff --git a/pkg/assembler/backends/neo4j/hasSBOM.go b/pkg/assembler/backends/neo4j/hasSBOM.go deleted file mode 100644 index 19a93ee04a..0000000000 --- a/pkg/assembler/backends/neo4j/hasSBOM.go +++ /dev/null @@ -1,200 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -const ( - uri string = "uri" -) - -func (c *neo4jClient) HasSBOMList(ctx context.Context, hasSBOMSpec model.HasSBOMSpec, after *string, first *int) (*model.HasSBOMConnection, error) { - return nil, fmt.Errorf("not implemented: HasSBOMList") -} - -// TODO: noe4j backend does not match the schema. This needs updating before use! -func (c *neo4jClient) HasSBOM(ctx context.Context, hasSBOMSpec *model.HasSBOMSpec) ([]*model.HasSbom, error) { - - queryAll := true - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - aggregateHasSBOM := []*model.HasSbom{} - - if queryAll || (hasSBOMSpec.Subject != nil && hasSBOMSpec.Subject.Package != nil) { - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - "version.qualifier_list, hasSBOM" - // query with pkgVersion - query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - "-[:subject]-(hasSBOM:HasSBOM)" - sb.WriteString(query) - - if hasSBOMSpec.Subject != nil && hasSBOMSpec.Subject.Package != nil { - setPkgMatchValues(&sb, hasSBOMSpec.Subject.Package, false, &firstMatch, queryValues) - } - setHasSBOMValues(&sb, hasSBOMSpec, &firstMatch, queryValues) - sb.WriteString(returnValue) - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedHasSBOM := []*model.HasSbom{} - - for result.Next() { - pkgQualifiers := result.Record().Values[5] - subPath := result.Record().Values[4] - version := result.Record().Values[3] - nameString := result.Record().Values[2].(string) - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - hasSBOMNode := dbtype.Node{} - if result.Record().Values[6] != nil { - hasSBOMNode = result.Record().Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("hasSBOM Node not found in neo4j") - } - - hasSBOM := generateModelHasSBOM(pkg, hasSBOMNode.Props[uri].(string), hasSBOMNode.Props[origin].(string), hasSBOMNode.Props[collector].(string)) - - collectedHasSBOM = append(collectedHasSBOM, hasSBOM) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedHasSBOM, nil - }) - if err != nil { - return nil, err - } - - aggregateHasSBOM = append(aggregateHasSBOM, result.([]*model.HasSbom)...) - } - - if queryAll || (hasSBOMSpec.Subject != nil && hasSBOMSpec.Subject.Artifact != nil) { - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - query := "MATCH (root:Src)-[:SrcHasType]->(type:SrcType)-[:SrcHasNamespace]->(namespace:SrcNamespace)" + - "-[:SrcHasName]->(name:SrcName)-[:subject]-(hasSBOM:HasSBOM)" - sb.WriteString(query) - - if hasSBOMSpec.Subject != nil && hasSBOMSpec.Subject.Artifact != nil { - setArtifactMatchValues(&sb, hasSBOMSpec.Subject.Artifact, false, &firstMatch, queryValues) - } - setHasSBOMValues(&sb, hasSBOMSpec, &firstMatch, queryValues) - sb.WriteString(" RETURN type.type, namespace.namespace, name.name, name.tag, name.commit, hasSBOM") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedHasSBOM := []*model.HasSbom{} - - for result.Next() { - algorithm := result.Record().Values[0].(string) - digest := result.Record().Values[1].(string) - - src := generateModelArtifact(algorithm, digest) - - hasSBOMNode := dbtype.Node{} - if result.Record().Values[5] != nil { - hasSBOMNode = result.Record().Values[5].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("hasSBOM Node not found in neo4j") - } - - hasSBOM := generateModelHasSBOM(src, hasSBOMNode.Props[uri].(string), hasSBOMNode.Props[origin].(string), hasSBOMNode.Props[collector].(string)) - - collectedHasSBOM = append(collectedHasSBOM, hasSBOM) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedHasSBOM, nil - }) - if err != nil { - return nil, err - } - aggregateHasSBOM = append(aggregateHasSBOM, result.([]*model.HasSbom)...) - } - - return aggregateHasSBOM, nil -} - -func setHasSBOMValues(sb *strings.Builder, hasSBOMSpec *model.HasSBOMSpec, firstMatch *bool, queryValues map[string]any) { - if hasSBOMSpec.URI != nil { - matchProperties(sb, *firstMatch, "hasSBOM", uri, "$"+uri) - *firstMatch = false - queryValues[uri] = hasSBOMSpec.URI - } - if hasSBOMSpec.Origin != nil { - matchProperties(sb, *firstMatch, "hasSBOM", origin, "$"+origin) - *firstMatch = false - queryValues[origin] = hasSBOMSpec.Origin - } - if hasSBOMSpec.Collector != nil { - matchProperties(sb, *firstMatch, "hasSBOM", collector, "$"+collector) - *firstMatch = false - queryValues[collector] = hasSBOMSpec.Collector - } -} - -func generateModelHasSBOM(subject model.PackageOrArtifact, uri, origin, collector string) *model.HasSbom { - hasSBOM := model.HasSbom{ - Subject: subject, - URI: uri, - Origin: origin, - Collector: collector, - } - return &hasSBOM -} - -func (c *neo4jClient) IngestHasSbom(ctx context.Context, subject model.PackageOrArtifactInput, hasSbom model.HasSBOMInputSpec, includes model.HasSBOMIncludesInputSpec) (string, error) { - panic(fmt.Errorf("not implemented: IngestHasSbom - IngestHasSbom")) -} - -func (c *neo4jClient) IngestHasSBOMs(ctx context.Context, subjects model.PackageOrArtifactInputs, hasSBOMs []*model.HasSBOMInputSpec, includes []*model.HasSBOMIncludesInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestHasSBOMs") -} diff --git a/pkg/assembler/backends/neo4j/hasSLSA.go b/pkg/assembler/backends/neo4j/hasSLSA.go deleted file mode 100644 index f9bba78861..0000000000 --- a/pkg/assembler/backends/neo4j/hasSLSA.go +++ /dev/null @@ -1,610 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" -) - -const ( - buildType string = "buildType" - predicate string = "predicate" - slsaVersion string = "slsaVersion" - startedOn string = "startedOn" - finishedOn string = "finishedOn" -) - -func (c *neo4jClient) HasSLSAList(ctx context.Context, hasSLSASpec model.HasSLSASpec, after *string, first *int) (*model.HasSLSAConnection, error) { - return nil, fmt.Errorf("not implemented: HasSLSAList") -} - -func (c *neo4jClient) HasSlsa(ctx context.Context, hasSLSASpec *model.HasSLSASpec) ([]*model.HasSlsa, error) { - // TODO update to not use PackageSourceOrArtifact - // session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - // defer session.Close() - - // queryAll := false - // //TODO(mihaimaruseac): Review this in e2e - // if hasSLSASpec.Subject == nil { - // queryAll = true - // } else if hasSLSASpec.Subject.Package == nil && hasSLSASpec.Subject.Source == nil && hasSLSASpec.Subject.Artifact == nil { - // queryAll = true - // } else { - // err := checkHasSLSAInputs(hasSLSASpec) - // if err != nil { - // return nil, err - // } - // } - - // aggregateHasSLSA := []*model.HasSlsa{} - - // if queryAll || (hasSLSASpec.Subject != nil && hasSLSASpec.Subject.Package != nil) { - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - // "version.qualifier_list, hasSLSA, b.uri, objArt.algorithm, objArt.digest, " + - // "objSrcType.type, objSrcNamespace.namespace, objSrcName.name, objSrcName.tag, objSrcName.commit, " + - // "objPkgType.type, objPkgNamespace.namespace, objPkgName.name, " + - // "objPkgVersion.version, objPkgVersion.subpath, objPkgVersion.qualifier_list" - // // query with pkgVersion - // query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - // "-[:subject]-(hasSLSA:HasSLSA)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:built_by]->(b:Builder)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objArt:Artifact)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objSrcName:SrcName)<-[:SrcHasName]-(objSrcNamespace:SrcNamespace)<-[:SrcHasNamespace]" + - // "-(objSrcType:SrcType)<-[:SrcHasType]-(objSrcRoot:Src)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objPkgVersion:PkgVersion)<-[:PkgHasVersion]-(objPkgName:PkgName)<-[:PkgHasName]" + - // "-(objPkgNamespace:PkgNamespace)<-[:PkgHasNamespace]" + - // "-(objPkgType:PkgType)<-[:PkgHasType]-(objPkgRoot:Pkg)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objPkgName:PkgName)<-[:PkgHasName]" + - // "-(objPkgNamespace:PkgNamespace)<-[:PkgHasNamespace]" + - // "-(objPkgType:PkgType)<-[:PkgHasType]-(objPkgRoot:Pkg)" + - // "\nWITH *, hasSLSA, null AS objPkgVersion" - - // sb.WriteString(query) - // setPkgMatchValues(&sb, hasSLSASpec.Subject.Package, false, &firstMatch, queryValues) - // setHasSLSAValues(&sb, hasSLSASpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // if hasSLSASpec.Subject.Package == nil || hasSLSASpec.Subject.Package != nil && hasSLSASpec.Subject.Package.Version == nil && hasSLSASpec.Subject.Package.Subpath == nil && - // len(hasSLSASpec.Subject.Package.Qualifiers) == 0 && !*hasSLSASpec.Subject.Package.MatchOnlyEmptyQualifiers { - - // sb.WriteString("\nUNION") - // // query without pkgVersion - // query := "\nMATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - // "-[:PkgHasName]->(name:PkgName)" + - // "-[:subject]-(hasSLSA:HasSLSA)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:built_by]->(b:Builder)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objArt:Artifact)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objSrcName:SrcName)<-[:SrcHasName]-(objSrcNamespace:SrcNamespace)<-[:SrcHasNamespace]" + - // "-(objSrcType:SrcType)<-[:SrcHasType]-(objSrcRoot:Src)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objPkgVersion:PkgVersion)<-[:PkgHasVersion]-(objPkgName:PkgName)<-[:PkgHasName]" + - // "-(objPkgNamespace:PkgNamespace)<-[:PkgHasNamespace]" + - // "-(objPkgType:PkgType)<-[:PkgHasType]-(objPkgRoot:Pkg)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objPkgName:PkgName)<-[:PkgHasName]" + - // "-(objPkgNamespace:PkgNamespace)<-[:PkgHasNamespace]" + - // "-(objPkgType:PkgType)<-[:PkgHasType]-(objPkgRoot:Pkg)" + - // "\nWITH *, hasSLSA, null AS version, null AS objPkgVersion" - - // sb.WriteString(query) - // firstMatch = true - // setPkgMatchValues(&sb, hasSLSASpec.Subject.Package, false, &firstMatch, queryValues) - // setHasSLSAValues(&sb, hasSLSASpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - // } - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // resultBuiltFromMap := map[model.PackageSourceOrArtifact][]model.PackageSourceOrArtifact{} - // resultHasSlsaMap := map[model.PackageSourceOrArtifact]*model.HasSlsa{} - // for result.Next() { - // pkgQualifiers := result.Record().Values[5] - // subPath := result.Record().Values[4] - // version := result.Record().Values[3] - // nameString := result.Record().Values[2].(string) - // namespaceString := result.Record().Values[1].(string) - // typeString := result.Record().Values[0].(string) - - // pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // if _, ok := resultHasSlsaMap[pkg]; !ok { - // uri := result.Record().Values[7].(string) - // builder := generateModelBuilder(uri) - // hasSLSANode := dbtype.Node{} - // if result.Record().Values[6] != nil { - // hasSLSANode = result.Record().Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("HasSLSA Node not found in neo4j") - // } - // hasSLSA := generateModelHasSLSA(pkg, builder, hasSLSANode.Props[predicate].([]interface{}), hasSLSANode.Props[buildType].(string), - // hasSLSANode.Props[slsaVersion].(string), hasSLSANode.Props[startedOn].(string), hasSLSANode.Props[finishedOn].(string), - // hasSLSANode.Props[origin].(time.Time), hasSLSANode.Props[collector].(time.Time)) - - // resultHasSlsaMap[pkg] = hasSLSA - // } - - // if _, ok := resultBuiltFromMap[pkg]; !ok { - // resultBuiltFromMap[pkg] = []model.PackageSourceOrArtifact{} - // } - - // if result.Record().Values[8] != nil && result.Record().Values[9] != nil { - - // algorithm := result.Record().Values[7].(string) - // digest := result.Record().Values[8].(string) - // objArt := generateModelArtifact(algorithm, digest) - - // if _, ok := resultBuiltFromMap[pkg]; ok { - // resultBuiltFromMap[pkg] = append(resultBuiltFromMap[pkg], objArt) - // } - // } - - // if result.Record().Values[10] != nil && result.Record().Values[11] != nil && result.Record().Values[12] != nil { - // tag := result.Record().Values[13] - // commit := result.Record().Values[14] - // nameStr := result.Record().Values[12].(string) - // namespaceStr := result.Record().Values[11].(string) - // srcType := result.Record().Values[10].(string) - - // objSrc := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - // if _, ok := resultBuiltFromMap[pkg]; ok { - // resultBuiltFromMap[pkg] = append(resultBuiltFromMap[pkg], objSrc) - // } - // } - - // if result.Record().Values[15] != nil && result.Record().Values[16] != nil && result.Record().Values[17] != nil { - - // pkgQualifiers := result.Record().Values[20] - // subPath := result.Record().Values[19] - // version := result.Record().Values[18] - // nameString := result.Record().Values[17].(string) - // namespaceString := result.Record().Values[16].(string) - // typeString := result.Record().Values[15].(string) - - // artPkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // if _, ok := resultBuiltFromMap[pkg]; ok { - // resultBuiltFromMap[pkg] = append(resultBuiltFromMap[pkg], artPkg) - // } - // } - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // collectedHasSLSA := []*model.HasSlsa{} - // for subject, hasSLSA := range resultHasSlsaMap { - // if builtFrom, ok := resultBuiltFromMap[subject]; ok { - // hasSLSA.Slsa.BuiltFrom = builtFrom - // } - // collectedHasSLSA = append(collectedHasSLSA, hasSLSA) - // } - // return collectedHasSLSA, nil - // }) - // if err != nil { - // return nil, err - // } - - // aggregateHasSLSA = append(aggregateHasSLSA, result.([]*model.HasSlsa)...) - // } - - // if queryAll || (hasSLSASpec.Subject != nil && hasSLSASpec.Subject.Source != nil) { - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // returnValue := " RETURN type.type, namespace.namespace, name.name, name.tag, name.commit, " + - // "hasSLSA, b.uri, objArt.algorithm, objArt.digest, " + - // "objSrcType.type, objSrcNamespace.namespace, objSrcName.name, objSrcName.tag, objSrcName.commit, " + - // "objPkgType.type, objPkgNamespace.namespace, objPkgName.name, " + - // "objPkgVersion.version, objPkgVersion.subpath, objPkgVersion.qualifier_list" - // // query with pkgVersion - // query := "MATCH (root:Src)-[:SrcHasType]->(type:SrcType)-[:SrcHasNamespace]->(namespace:SrcNamespace)" + - // "-[:SrcHasName]->(name:SrcName)" + - // "-[:subject]-(hasSLSA:HasSLSA)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:built_by]->(b:Builder)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objArt:Artifact)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objSrcName:SrcName)<-[:SrcHasName]-(objSrcNamespace:SrcNamespace)<-[:SrcHasNamespace]" + - // "-(objSrcType:SrcType)<-[:SrcHasType]-(objSrcRoot:Src)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objPkgVersion:PkgVersion)<-[:PkgHasVersion]-(objPkgName:PkgName)<-[:PkgHasName]" + - // "-(objPkgNamespace:PkgNamespace)<-[:PkgHasNamespace]" + - // "-(objPkgType:PkgType)<-[:PkgHasType]-(objPkgRoot:Pkg)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objPkgName:PkgName)<-[:PkgHasName]" + - // "-(objPkgNamespace:PkgNamespace)<-[:PkgHasNamespace]" + - // "-(objPkgType:PkgType)<-[:PkgHasType]-(objPkgRoot:Pkg)" + - // "\nWITH *, hasSLSA, null AS objPkgVersion" - - // sb.WriteString(query) - // setSrcMatchValues(&sb, hasSLSASpec.Subject.Source, false, &firstMatch, queryValues) - // setHasSLSAValues(&sb, hasSLSASpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // resultBuiltFromMap := map[model.PackageSourceOrArtifact][]model.PackageSourceOrArtifact{} - // resultHasSlsaMap := map[model.PackageSourceOrArtifact]*model.HasSlsa{} - - // for result.Next() { - // tag := result.Record().Values[3] - // commit := result.Record().Values[4] - // nameStr := result.Record().Values[2].(string) - // namespaceStr := result.Record().Values[1].(string) - // srcType := result.Record().Values[0].(string) - - // src := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - // if _, ok := resultHasSlsaMap[src]; !ok { - // uri := result.Record().Values[6].(string) - // builder := generateModelBuilder(uri) - - // hasSLSANode := dbtype.Node{} - // if result.Record().Values[5] != nil { - // hasSLSANode = result.Record().Values[5].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("HasSLSA Node not found in neo4j") - // } - // hasSLSA := generateModelHasSLSA(src, builder, hasSLSANode.Props[predicate].([]interface{}), hasSLSANode.Props[buildType].(string), - // hasSLSANode.Props[slsaVersion].(string), hasSLSANode.Props[startedOn].(string), hasSLSANode.Props[finishedOn].(string), - // hasSLSANode.Props[origin].(time.Time), hasSLSANode.Props[collector].(time.Time)) - - // resultHasSlsaMap[src] = hasSLSA - // } - - // if _, ok := resultBuiltFromMap[src]; !ok { - // resultBuiltFromMap[src] = []model.PackageSourceOrArtifact{} - // } - - // if result.Record().Values[7] != nil && result.Record().Values[8] != nil { - // algorithm := result.Record().Values[7].(string) - // digest := result.Record().Values[8].(string) - // objArt := generateModelArtifact(algorithm, digest) - // if _, ok := resultBuiltFromMap[src]; ok { - // resultBuiltFromMap[src] = append(resultBuiltFromMap[src], objArt) - // } - // } - - // if result.Record().Values[9] != nil && result.Record().Values[10] != nil && result.Record().Values[11] != nil { - // tag := result.Record().Values[12] - // commit := result.Record().Values[13] - // nameStr := result.Record().Values[11].(string) - // namespaceStr := result.Record().Values[10].(string) - // srcType := result.Record().Values[9].(string) - - // objSrc := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - // if _, ok := resultBuiltFromMap[src]; ok { - // resultBuiltFromMap[src] = append(resultBuiltFromMap[src], objSrc) - // } - // } - - // if result.Record().Values[14] != nil && result.Record().Values[15] != nil && result.Record().Values[16] != nil { - // pkgQualifiers := result.Record().Values[19] - // subPath := result.Record().Values[18] - // version := result.Record().Values[17] - // nameString := result.Record().Values[16].(string) - // namespaceString := result.Record().Values[15].(string) - // typeString := result.Record().Values[14].(string) - - // artPkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - // if _, ok := resultBuiltFromMap[src]; ok { - // resultBuiltFromMap[src] = append(resultBuiltFromMap[src], artPkg) - // } - // } - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // collectedHasSLSA := []*model.HasSlsa{} - // for subject, hasSLSA := range resultHasSlsaMap { - // if builtFrom, ok := resultBuiltFromMap[subject]; ok { - // hasSLSA.Slsa.BuiltFrom = builtFrom - // } - // collectedHasSLSA = append(collectedHasSLSA, hasSLSA) - // } - - // return collectedHasSLSA, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateHasSLSA = append(aggregateHasSLSA, result.([]*model.HasSlsa)...) - // } - - // if queryAll || (hasSLSASpec.Subject != nil && hasSLSASpec.Subject.Artifact != nil) { - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // returnValue := " RETURN a.algorithm, a.digest, " + - // "hasSLSA, b.uri, objArt.algorithm, objArt.digest, " + - // "objSrcType.type, objSrcNamespace.namespace, objSrcName.name, objSrcName.tag, objSrcName.commit, " + - // "objPkgType.type, objPkgNamespace.namespace, objPkgName.name, " + - // "objPkgVersion.version, objPkgVersion.subpath, objPkgVersion.qualifier_list" - // // query with pkgVersion - // query := "MATCH (a:Artifact)-[:subject]-(hasSLSA:HasSLSA)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:built_by]->(b:Builder)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objArt:Artifact)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objSrcName:SrcName)<-[:SrcHasName]-(objSrcNamespace:SrcNamespace)<-[:SrcHasNamespace]" + - // "-(objSrcType:SrcType)<-[:SrcHasType]-(objSrcRoot:Src)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objPkgVersion:PkgVersion)<-[:PkgHasVersion]-(objPkgName:PkgName)<-[:PkgHasName]" + - // "-(objPkgNamespace:PkgNamespace)<-[:PkgHasNamespace]" + - // "-(objPkgType:PkgType)<-[:PkgHasType]-(objPkgRoot:Pkg)" + - // "\nWITH *, hasSLSA" + - // "\nMATCH (hasSLSA)-[:BuildFrom]->(objPkgName:PkgName)<-[:PkgHasName]" + - // "-(objPkgNamespace:PkgNamespace)<-[:PkgHasNamespace]" + - // "-(objPkgType:PkgType)<-[:PkgHasType]-(objPkgRoot:Pkg)" + - // "\nWITH *, hasSLSA, null AS objPkgVersion" - - // sb.WriteString(query) - // setArtifactMatchValues(&sb, hasSLSASpec.Subject.Artifact, false, &firstMatch, queryValues) - // setHasSLSAValues(&sb, hasSLSASpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // resultBuiltFromMap := map[model.PackageSourceOrArtifact][]model.PackageSourceOrArtifact{} - // resultHasSlsaMap := map[model.PackageSourceOrArtifact]*model.HasSlsa{} - - // for result.Next() { - // algorithm := result.Record().Values[0].(string) - // digest := result.Record().Values[1].(string) - // artifact := generateModelArtifact(algorithm, digest) - - // if _, ok := resultHasSlsaMap[artifact]; !ok { - // uri := result.Record().Values[3].(string) - // builder := generateModelBuilder(uri) - - // hasSLSANode := dbtype.Node{} - // if result.Record().Values[2] != nil { - // hasSLSANode = result.Record().Values[2].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("HasSLSA Node not found in neo4j") - // } - // hasSLSA := generateModelHasSLSA(artifact, builder, hasSLSANode.Props[predicate].([]interface{}), hasSLSANode.Props[buildType].(string), - // hasSLSANode.Props[slsaVersion].(string), hasSLSANode.Props[startedOn].(string), hasSLSANode.Props[finishedOn].(string), - // hasSLSANode.Props[origin].(time.Time), hasSLSANode.Props[collector].(time.Time)) - - // resultHasSlsaMap[artifact] = hasSLSA - // } - - // if _, ok := resultBuiltFromMap[artifact]; !ok { - // resultBuiltFromMap[artifact] = []model.PackageSourceOrArtifact{} - // } - - // if result.Record().Values[4] != nil && result.Record().Values[5] != nil { - // algorithm := result.Record().Values[4].(string) - // digest := result.Record().Values[5].(string) - // objArt := generateModelArtifact(algorithm, digest) - // if _, ok := resultBuiltFromMap[artifact]; ok { - // resultBuiltFromMap[artifact] = append(resultBuiltFromMap[artifact], objArt) - // } - // } - - // if result.Record().Values[6] != nil && result.Record().Values[7] != nil && result.Record().Values[8] != nil { - // tag := result.Record().Values[9] - // commit := result.Record().Values[10] - // nameStr := result.Record().Values[8].(string) - // namespaceStr := result.Record().Values[7].(string) - // srcType := result.Record().Values[6].(string) - - // objSrc := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - // if _, ok := resultBuiltFromMap[artifact]; ok { - // resultBuiltFromMap[artifact] = append(resultBuiltFromMap[artifact], objSrc) - // } - // } - - // if result.Record().Values[13] != nil && result.Record().Values[12] != nil && result.Record().Values[11] != nil { - - // pkgQualifiers := result.Record().Values[16] - // subPath := result.Record().Values[15] - // version := result.Record().Values[14] - // nameString := result.Record().Values[13].(string) - // namespaceString := result.Record().Values[12].(string) - // typeString := result.Record().Values[11].(string) - - // artPkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - // if _, ok := resultBuiltFromMap[artifact]; ok { - // resultBuiltFromMap[artifact] = append(resultBuiltFromMap[artifact], artPkg) - // } - // } - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // collectedHasSLSA := []*model.HasSlsa{} - // for subject, hasSLSA := range resultHasSlsaMap { - // if builtFrom, ok := resultBuiltFromMap[subject]; ok { - // hasSLSA.Slsa.BuiltFrom = builtFrom - // } - // collectedHasSLSA = append(collectedHasSLSA, hasSLSA) - // } - - // return collectedHasSLSA, nil - // }) - // if err != nil { - // return nil, err - // } - - // aggregateHasSLSA = append(aggregateHasSLSA, result.([]*model.HasSlsa)...) - // } - // return aggregateHasSLSA, nil - return nil, nil -} - -// TODO update to not use PackageSourceOrArtifact - -// TODO(pxp928): combine with testing backend in shared utility -// func checkHasSLSAInputs(hasSLSASpec *model.HasSLSASpec) error { -// subjectsDefined := 0 -// if hasSLSASpec.Subject.Package != nil { -// subjectsDefined = subjectsDefined + 1 -// } -// if hasSLSASpec.Subject.Source != nil { -// subjectsDefined = subjectsDefined + 1 -// } -// if hasSLSASpec.Subject.Artifact != nil { -// subjectsDefined = subjectsDefined + 1 -// } -// if subjectsDefined > 1 { -// return gqlerror.Errorf("Must specify at most one subject (package, source, or artifact)") -// } -// return nil -// } - -// func getCollectedPredicate(predicateList []interface{}) []*model.SLSAPredicate { -// predicate := []*model.SLSAPredicate{} -// for i := range predicateList { -// if i%2 == 0 { -// value := &model.SLSAPredicate{ -// Key: predicateList[i].(string), -// Value: predicateList[i+1].(string), -// } -// predicate = append(predicate, value) -// } -// } -// return predicate -// } - -// func getPredicateValuesFromSpec(slsaPredicate []*model.SLSAPredicateSpec) []string { -// predicateMap := map[string]string{} -// keys := []string{} -// for _, kv := range slsaPredicate { -// key := removeInvalidCharFromProperty(kv.Key) -// predicateMap[key] = kv.Value -// keys = append(keys, key) -// } -// sort.Strings(keys) -// predicateValues := []string{} -// for _, k := range keys { -// predicateValues = append(predicateValues, k, predicateMap[k]) -// } -// return predicateValues -// } - -// func setHasSLSAValues(sb *strings.Builder, hasSLSASpec *model.HasSLSASpec, firstMatch *bool, queryValues map[string]any) { -// if hasSLSASpec.BuildType != nil { -// matchProperties(sb, *firstMatch, "hasSLSA", buildType, "$"+buildType) -// *firstMatch = false -// queryValues[buildType] = hasSLSASpec.BuildType -// } -// if len(hasSLSASpec.Predicate) > 0 { -// predicateValues := getPredicateValuesFromSpec(hasSLSASpec.Predicate) -// matchProperties(sb, *firstMatch, "hasSLSA", predicate, "$"+predicate) -// *firstMatch = false -// queryValues[predicate] = predicateValues -// } -// if hasSLSASpec.SlsaVersion != nil { -// matchProperties(sb, *firstMatch, "hasSLSA", slsaVersion, "$"+slsaVersion) -// *firstMatch = false -// queryValues[slsaVersion] = hasSLSASpec.SlsaVersion -// } -// if hasSLSASpec.StartedOn != nil { -// matchProperties(sb, *firstMatch, "hasSLSA", startedOn, "$"+startedOn) -// *firstMatch = false -// queryValues[startedOn] = hasSLSASpec.StartedOn -// } -// if hasSLSASpec.FinishedOn != nil { -// matchProperties(sb, *firstMatch, "hasSLSA", finishedOn, "$"+finishedOn) -// *firstMatch = false -// queryValues[finishedOn] = hasSLSASpec.FinishedOn -// } -// if hasSLSASpec.Origin != nil { -// matchProperties(sb, *firstMatch, "hasSLSA", "origin", "$origin") -// *firstMatch = false -// queryValues["origin"] = hasSLSASpec.Origin -// } -// if hasSLSASpec.Collector != nil { -// matchProperties(sb, *firstMatch, "hasSLSA", "collector", "$collector") -// *firstMatch = false -// queryValues["collector"] = hasSLSASpec.Collector -// } -// } - -// func generateModelHasSLSA(subject model.PackageSourceOrArtifact, -// builder *model.Builder, slsaPredicate []interface{}, buildType, -// slsaVersion, origin, collector string, -// startedOn, finishedOn time.Time) *model.HasSlsa { -// slsa := &model.Slsa{ -// BuiltBy: builder, -// BuildType: buildType, -// SlsaPredicate: getCollectedPredicate(slsaPredicate), -// SlsaVersion: slsaVersion, -// StartedOn: startedOn, -// FinishedOn: finishedOn, -// Origin: origin, -// Collector: collector, -// } -// hasSLSA := model.HasSlsa{ -// Subject: subject, -// Slsa: slsa, -// } -// return &hasSLSA -// } - -func (c *neo4jClient) IngestSLSA(ctx context.Context, subject model.IDorArtifactInput, builtFrom []*model.IDorArtifactInput, builtBy model.IDorBuilderInput, slsa model.SLSAInputSpec) (string, error) { - panic(fmt.Errorf("not implemented: IngestSlsa - ingestSLSA")) -} - -func (c *neo4jClient) IngestSLSAs(ctx context.Context, subjects []*model.IDorArtifactInput, builtFromList [][]*model.IDorArtifactInput, builtByList []*model.IDorBuilderInput, slsaList []*model.SLSAInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestSLSAs") -} diff --git a/pkg/assembler/backends/neo4j/hasSourceAt.go b/pkg/assembler/backends/neo4j/hasSourceAt.go deleted file mode 100644 index 39b0f9dee2..0000000000 --- a/pkg/assembler/backends/neo4j/hasSourceAt.go +++ /dev/null @@ -1,171 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -const ( - knownSince string = "knownSince" -) - -func (c *neo4jClient) HasSourceAtList(ctx context.Context, hasSourceAtSpec model.HasSourceAtSpec, after *string, first *int) (*model.HasSourceAtConnection, error) { - return nil, fmt.Errorf("not implemented: HasSourceAtList") -} - -func (c *neo4jClient) HasSourceAt(ctx context.Context, hasSourceAtSpec *model.HasSourceAtSpec) ([]*model.HasSourceAt, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - - returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - "version.qualifier_list, hasSourceAt, objSrcType.type, objSrcNamespace.namespace, objSrcName.name, objSrcName.tag, objSrcName.commit" - - queryValues := map[string]any{} - // query with pkgVersion - query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - "-[:subject]-(hasSourceAt:HasSourceAt)-[:has_source]-(objSrcName:SrcName)<-[:SrcHasName]-(objSrcNamespace:SrcNamespace)<-[:SrcHasNamespace]" + - "-(objSrcType:SrcType)<-[:SrcHasType]-(objSrcRoot:Src)" - sb.WriteString(query) - - setPkgMatchValues(&sb, hasSourceAtSpec.Package, false, &firstMatch, queryValues) - setSrcMatchValues(&sb, hasSourceAtSpec.Source, true, &firstMatch, queryValues) - setHasSourceAtValues(&sb, hasSourceAtSpec, &firstMatch, queryValues) - sb.WriteString(returnValue) - - if hasSourceAtSpec.Package == nil || hasSourceAtSpec.Package != nil && hasSourceAtSpec.Package.Version == nil && hasSourceAtSpec.Package.Subpath == nil && - len(hasSourceAtSpec.Package.Qualifiers) == 0 && !*hasSourceAtSpec.Package.MatchOnlyEmptyQualifiers { - - sb.WriteString("\nUNION") - // query without pkgVersion - query = "\nMATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)" + - "-[:subject]-(hasSourceAt:HasSourceAt)-[:has_source]-(objSrcName:SrcName)<-[:SrcHasName]-(objSrcNamespace:SrcNamespace)<-[:SrcHasNamespace]" + - "-(objSrcType:SrcType)<-[:SrcHasType]-(objSrcRoot:Src)" + - "\nWITH *, null AS version" - sb.WriteString(query) - - firstMatch = true - setPkgMatchValues(&sb, hasSourceAtSpec.Package, false, &firstMatch, queryValues) - setSrcMatchValues(&sb, hasSourceAtSpec.Source, true, &firstMatch, queryValues) - setHasSourceAtValues(&sb, hasSourceAtSpec, &firstMatch, queryValues) - sb.WriteString(returnValue) - } - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedHasSourceAt := []*model.HasSourceAt{} - - for result.Next() { - pkgQualifiers := result.Record().Values[5] - subPath := result.Record().Values[4] - version := result.Record().Values[3] - nameString := result.Record().Values[2].(string) - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - tag := result.Record().Values[10] - commit := result.Record().Values[11] - nameStr := result.Record().Values[9].(string) - namespaceStr := result.Record().Values[8].(string) - srcType := result.Record().Values[7].(string) - - src := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - hasSourceAtNode := dbtype.Node{} - if result.Record().Values[6] != nil { - hasSourceAtNode = result.Record().Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("hasSourceAt Node not found in neo4j") - } - - hasSourceAt := &model.HasSourceAt{ - Package: pkg, - Source: src, - KnownSince: hasSourceAtNode.Props[knownSince].(time.Time), - Justification: hasSourceAtNode.Props[justification].(string), - Origin: hasSourceAtNode.Props[origin].(string), - Collector: hasSourceAtNode.Props[collector].(string), - } - collectedHasSourceAt = append(collectedHasSourceAt, hasSourceAt) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedHasSourceAt, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.HasSourceAt), nil -} - -func setHasSourceAtValues(sb *strings.Builder, hasSourceAtSpec *model.HasSourceAtSpec, firstMatch *bool, queryValues map[string]any) { - if hasSourceAtSpec.KnownSince != nil { - - matchProperties(sb, *firstMatch, "hasSourceAt", "knownSince", "$knownSince") - *firstMatch = false - queryValues["knownSince"] = hasSourceAtSpec.KnownSince.UTC() - } - if hasSourceAtSpec.Justification != nil { - - matchProperties(sb, *firstMatch, "hasSourceAt", "justification", "$justification") - *firstMatch = false - queryValues["justification"] = hasSourceAtSpec.Justification - } - if hasSourceAtSpec.Origin != nil { - - matchProperties(sb, *firstMatch, "hasSourceAt", "origin", "$origin") - *firstMatch = false - queryValues["origin"] = hasSourceAtSpec.Origin - } - if hasSourceAtSpec.Collector != nil { - - matchProperties(sb, *firstMatch, "hasSourceAt", "collector", "$collector") - *firstMatch = false - queryValues["collector"] = hasSourceAtSpec.Collector - } -} - -func (c *neo4jClient) IngestHasSourceAt(ctx context.Context, pkg model.IDorPkgInput, pkgMatchType model.MatchFlags, source model.IDorSourceInput, hasSourceAt model.HasSourceAtInputSpec) (string, error) { - panic(fmt.Errorf("not implemented: IngestHasSourceAt")) -} - -func (c *neo4jClient) IngestHasSourceAts(ctx context.Context, pkgs []*model.IDorPkgInput, pkgMatchType *model.MatchFlags, sources []*model.IDorSourceInput, hasSourceAts []*model.HasSourceAtInputSpec) ([]string, error) { - panic(fmt.Errorf("not implemented: IngestHasSourceAts")) -} diff --git a/pkg/assembler/backends/neo4j/hashEqual.go b/pkg/assembler/backends/neo4j/hashEqual.go deleted file mode 100644 index 187047757a..0000000000 --- a/pkg/assembler/backends/neo4j/hashEqual.go +++ /dev/null @@ -1,151 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -func (c *neo4jClient) HashEqualList(ctx context.Context, hashEqualSpec model.HashEqualSpec, after *string, first *int) (*model.HashEqualConnection, error) { - return nil, fmt.Errorf("not implemented: HashEqualList") -} - -func (c *neo4jClient) HashEqual(ctx context.Context, hashEqualSpec *model.HashEqualSpec) ([]*model.HashEqual, error) { - - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - - var selectedArt *model.ArtifactSpec = nil - var dependentArt *model.ArtifactSpec = nil - if hashEqualSpec.Artifacts != nil && len(hashEqualSpec.Artifacts) != 0 { - if len(hashEqualSpec.Artifacts) == 1 { - selectedArt = hashEqualSpec.Artifacts[0] - } else { - selectedArt = hashEqualSpec.Artifacts[0] - dependentArt = hashEqualSpec.Artifacts[1] - } - } - queryValues := map[string]any{} - - returnValue := " RETURN a.algorithm, a.digest, hashEqual, objArt.algorithm, objArt.digest" - - // query with selectedArt being subject - query := "MATCH (a:Artifact)-[:subject]-(hashEqual:HashEqual)-[:is_equal]-(objArt:Artifact)" - sb.WriteString(query) - - setArtifactMatchValues(&sb, selectedArt, false, &firstMatch, queryValues) - setArtifactMatchValues(&sb, dependentArt, true, &firstMatch, queryValues) - setHashEqualValues(&sb, hashEqualSpec, &firstMatch, queryValues) - - sb.WriteString(returnValue) - - if len(hashEqualSpec.Artifacts) > 0 { - sb.WriteString("\nUNION") - - // query with dependentArt being subject - query = "\nMATCH (a:Artifact)-[:subject]-(hashEqual:HashEqual)-[:is_equal]-(objArt:Artifact)" - sb.WriteString(query) - - firstMatch = true - setArtifactMatchValues(&sb, dependentArt, false, &firstMatch, queryValues) - setArtifactMatchValues(&sb, selectedArt, true, &firstMatch, queryValues) - setHashEqualValues(&sb, hashEqualSpec, &firstMatch, queryValues) - - sb.WriteString(returnValue) - } - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedHashEqual := []*model.HashEqual{} - - for result.Next() { - - algorithm := result.Record().Values[0].(string) - digest := result.Record().Values[1].(string) - artifact := generateModelArtifact(algorithm, digest) - - algorithm = result.Record().Values[3].(string) - digest = result.Record().Values[4].(string) - depArtifact := generateModelArtifact(algorithm, digest) - - hashEqualNode := dbtype.Node{} - if result.Record().Values[2] != nil { - hashEqualNode = result.Record().Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("hashEqual Node not found in neo4j") - } - - hashEqual := &model.HashEqual{ - Artifacts: []*model.Artifact{artifact, depArtifact}, - Justification: hashEqualNode.Props[justification].(string), - Origin: hashEqualNode.Props[origin].(string), - Collector: hashEqualNode.Props[collector].(string), - } - collectedHashEqual = append(collectedHashEqual, hashEqual) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedHashEqual, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.HashEqual), nil -} - -func setHashEqualValues(sb *strings.Builder, hashEqualSpec *model.HashEqualSpec, firstMatch *bool, queryValues map[string]any) { - if hashEqualSpec.Justification != nil { - matchProperties(sb, *firstMatch, "hashEqual", "justification", "$justification") - *firstMatch = false - queryValues["justification"] = hashEqualSpec.Justification - } - if hashEqualSpec.Origin != nil { - matchProperties(sb, *firstMatch, "hashEqual", "origin", "$origin") - *firstMatch = false - queryValues["origin"] = hashEqualSpec.Origin - } - if hashEqualSpec.Collector != nil { - matchProperties(sb, *firstMatch, "hashEqual", "collector", "$collector") - *firstMatch = false - queryValues["collector"] = hashEqualSpec.Collector - } -} - -func (c *neo4jClient) IngestHashEqual(ctx context.Context, artifact model.IDorArtifactInput, equalArtifact model.IDorArtifactInput, hashEqual model.HashEqualInputSpec) (string, error) { - panic(fmt.Errorf("not implemented: IngestHashEqual - IngestHashEqual")) -} - -func (c *neo4jClient) IngestHashEquals(ctx context.Context, artifacts []*model.IDorArtifactInput, otherArtifacts []*model.IDorArtifactInput, hashEquals []*model.HashEqualInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestHashEquals") -} diff --git a/pkg/assembler/backends/neo4j/ingest_testdata.go b/pkg/assembler/backends/neo4j/ingest_testdata.go deleted file mode 100644 index a0b3281e6c..0000000000 --- a/pkg/assembler/backends/neo4j/ingest_testdata.go +++ /dev/null @@ -1,287 +0,0 @@ -// -// 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 neo4j - -func registerAllArtifacts(client *neo4jClient) error { - // strings.ToLower(string(checksum.Algorithm)) + ":" + checksum.Value - err := client.registerArtifact("sha256", "6bbb0da1891646e58eb3e6a63af3a6fc3c8eb5a0d44824cba581d2e14a0450cf") - if err != nil { - return err - } - err = client.registerArtifact("sha1", "7A8F47318E4676DACB0142AFA0B83029CD7BEFD9") - if err != nil { - return err - } - err = client.registerArtifact("sha512", "374AB8F711235830769AA5F0B31CE9B72C5670074B34CB302CDAFE3B606233EE92EE01E298E5701F15CC7087714CD9ABD7DDB838A6E1206B3642DE16D9FC9DD7") - if err != nil { - return err - } - return nil -} - -func registerAllBuilders(client *neo4jClient) error { - err := client.registerBuilder("https://github.com/Attestations/GitHubHostedActions@v1") - if err != nil { - return err - } - err = client.registerBuilder("https://tekton.dev/chains/v2") - if err != nil { - return err - } - return nil -} - -func registerAllCVE(client *neo4jClient) error { - err := client.registerCVE("2019", "CVE-2019-13110") - if err != nil { - return err - } - err = client.registerCVE("2014", "CVE-2014-8139") - if err != nil { - return err - } - err = client.registerCVE("2014", "CVE-2014-8140") - if err != nil { - return err - } - err = client.registerCVE("2022", "CVE-2022-26499") - if err != nil { - return err - } - err = client.registerCVE("2014", "CVE-2014-8140") - if err != nil { - return err - } - return nil -} - -func registerAllGHSA(client *neo4jClient) error { - err := client.registerGhsa("GHSA-h45f-rjvw-2rv2") - if err != nil { - return err - } - err = client.registerGhsa("GHSA-xrw3-wqph-3fxg") - if err != nil { - return err - } - err = client.registerGhsa("GHSA-8v4j-7jgf-5rg9") - if err != nil { - return err - } - return nil -} - -func registerAllOSV(client *neo4jClient) error { - err := client.registerOSV("CVE-2019-13110") - if err != nil { - return err - } - err = client.registerOSV("CVE-2014-8139") - if err != nil { - return err - } - err = client.registerOSV("CVE-2014-8140") - if err != nil { - return err - } - err = client.registerOSV("CVE-2022-26499") - if err != nil { - return err - } - err = client.registerOSV("GHSA-h45f-rjvw-2rv2") - if err != nil { - return err - } - return nil -} - -func registerAllPackages(client *neo4jClient) error { - // TODO: add util to convert from pURL to package fields - // pkg:apk/alpine/apk@2.12.9-r3?arch=x86 - err := client.registerPackage("apk", "alpine", "apk", "2.12.9-r3", "", "arch=x86") - if err != nil { - return err - } - // pkg:apk/alpine/curl@7.83.0-r0?arch=x86 - err = client.registerPackage("apk", "alpine", "curl", "7.83.0-r0", "", "arch=x86") - if err != nil { - return err - } - // pkg:conan/openssl.org/openssl@3.0.3?arch=x86_64&build_type=Debug&compiler=Visual%20Studio&compiler.runtime=MDd&compiler.version=16&os=Windows&shared=True&rrev=93a82349c31917d2d674d22065c7a9ef9f380c8e&prev=b429db8a0e324114c25ec387bfd8281f330d7c5c - // NOTE: neo4j does not like "." for its property. "compiler.runtime" has to be changed to "compiler_runtime" - err = client.registerPackage("conan", "openssl.org", "openssl", "3.0.3", "", "arch=x86_64", "build_type=Debug", "compiler=Visual%20Studio", "compiler_runtime=MDd", "compiler_version=16", "os=Windows", "shared=True", "rrev=93a82349c31917d2d674d22065c7a9ef9f380c8e", "prev=b429db8a0e324114c25ec387bfd8281f330d7c5c") - if err != nil { - return err - } - // pkg:conan/openssl.org/openssl@3.0.3?user=bincrafters&channel=stable - err = client.registerPackage("conan", "openssl.org", "openssl", "3.0.3", "", "user=bincrafters", "channel=stable") - if err != nil { - return err - } - // pkg:conan/openssl@3.0.3 - err = client.registerPackage("conan", "", "openssl", "3.0.3", "") - if err != nil { - return err - } - // pkg:deb/debian/attr@1:2.4.47-2?arch=amd64 - err = client.registerPackage("deb", "debian", "attr", "1:2.4.47-2", "", "arch=amd64") - if err != nil { - return err - } - // pkg:deb/debian/attr@1:2.4.47-2?arch=source - err = client.registerPackage("deb", "debian", "attr", "1:2.4.47-2", "", "arch=source") - if err != nil { - return err - } - // pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie - err = client.registerPackage("deb", "debian", "curl", "7.50.3-1", "", "arch=i386", "distro=jessie") - if err != nil { - return err - } - // pkg:deb/debian/dpkg@1.19.0.4?arch=amd64&distro=stretch - err = client.registerPackage("deb", "debian", "dpkg", "1.19.0.4", "", "arch=amd64", "distro=stretch") - if err != nil { - return err - } - // pkg:deb/ubuntu/dpkg@1.19.0.4?arch=amd64 - err = client.registerPackage("deb", "ubuntu", "dpkg", "1.19.0.4", "", "arch=amd64") - if err != nil { - return err - } - // pkg:docker/cassandra@latest - err = client.registerPackage("docker", "", "cassandra", "latest", "") - if err != nil { - return err - } - // pkg:docker/cassandra@sha256:244fd47e07d1004f0aed9c - err = client.registerPackage("docker", "", "cassandra", "sha256:244fd47e07d1004f0aed9c", "") - if err != nil { - return err - } - // pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io - err = client.registerPackage("docker", "customer", "dockerimage", "sha256:244fd47e07d1004f0aed9c", "", "repository_url=gcr.io") - if err != nil { - return err - } - // pkg:docker/smartentry/debian@dc437cc87d10 - err = client.registerPackage("docker", "smartentry", "debian", "dc437cc87d10", "") - if err != nil { - return err - } - // pkg:generic/bitwarderl?vcs_url=git%2Bhttps://git.fsfe.org/dxtr/bitwarderl%40cc55108da32 - err = client.registerPackage("generic", "", "bitwarderl", "", "", "vcs_url=git%2Bhttps://git.fsfe.org/dxtr/bitwarderl%40cc55108da32") - if err != nil { - return err - } - // pkg:generic/openssl@1.1.10g - err = client.registerPackage("generic", "", "openssl", "1.1.10g", "") - if err != nil { - return err - } - // pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz&checksum=sha256:de4d501267da - err = client.registerPackage("generic", "", "openssl", "1.1.10g", "", "download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz", "checksum=sha256:de4d501267da") - if err != nil { - return err - } - // pkg:oci/debian@sha256:244fd47e07d10?repository_url=ghcr.io/debian&tag=bullseye - err = client.registerPackage("oci", "", "debian", "sha256:244fd47e07d10", "", "repository_url=ghcr.io/debian", "tag=bullseye") - if err != nil { - return err - } - // pkg:oci/hello-wasm@sha256:244fd47e07d10?tag=v1 - err = client.registerPackage("oci", "", "hello-wasm", "sha256:244fd47e07d10", "", "tag=v1") - if err != nil { - return err - } - // pkg:oci/static@sha256:244fd47e07d10?repository_url=gcr.io/distroless/static&tag=latest - err = client.registerPackage("oci", "", "static", "sha256:244fd47e07d10", "", "repository_url=gcr.io/distroless/static", "tag=latest") - if err != nil { - return err - } - // pkg:pypi/django-allauth@12.23 - err = client.registerPackage("pypi", "", "django-allauth", "12.23", "") - if err != nil { - return err - } - // pkg:pypi/django@1.11.1 - err = client.registerPackage("pypi", "", "django", "1.11.1", "") - if err != nil { - return err - } - // pkg:pypi/django@1.11.1#subpath - err = client.registerPackage("pypi", "", "django", "1.11.1", "subpath") - if err != nil { - return err - } - return nil -} - -func registerAllSources(client *neo4jClient) error { - // with tag - err := client.registerSource("git", "github", "github.com/guacsec/guac", "tag=v0.0.1") - if err != nil { - return err - } - // with commit - err = client.registerSource("git", "github", "github.com/guacsec/guac", "commit=fcba958b73e27cad8b5c8655d46439984d27853b") - if err != nil { - return err - } - // with no tag or commit - err = client.registerSource("git", "github", "github.com/guacsec/guac", "") - if err != nil { - return err - } - // gitlab namespace - err = client.registerSource("git", "gitlab", "github.com/guacsec/guacdata", "tag=v0.0.1") - if err != nil { - return err - } - // differnt type - err = client.registerSource("svn", "gitlab", "github.com/guacsec/guac", "") - if err != nil { - return err - } - return nil -} - -func (c *neo4jClient) registerArtifact(algorithm, digest string) error { - return nil -} - -func (c *neo4jClient) registerBuilder(uri string) error { - return nil -} - -func (c *neo4jClient) registerCVE(year, id string) error { - return nil -} - -func (c *neo4jClient) registerGhsa(id string) error { - return nil -} - -func (c *neo4jClient) registerOSV(id string) error { - return nil -} - -func (c *neo4jClient) registerPackage(packageType, namespace, name, version, subpath string, qualifiers ...string) error { - return nil -} - -func (c *neo4jClient) registerSource(sourceType, namespace, name, qualifier string) error { - return nil -} diff --git a/pkg/assembler/backends/neo4j/isDependency.go b/pkg/assembler/backends/neo4j/isDependency.go deleted file mode 100644 index a7db478711..0000000000 --- a/pkg/assembler/backends/neo4j/isDependency.go +++ /dev/null @@ -1,280 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - - "github.com/guacsec/guac/pkg/assembler/backends/helper" - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -const ( - dependencyType string = "dependencyType" -) - -// Query IsDependency - -func (c *neo4jClient) IsDependencyList(ctx context.Context, isDependencySpec model.IsDependencySpec, after *string, first *int) (*model.IsDependencyConnection, error) { - return nil, fmt.Errorf("not implemented: IsDependencyList") -} - -// note this has not been optimized to remove pkgVersion -> pkgName -func (c *neo4jClient) IsDependency(ctx context.Context, isDependencySpec *model.IsDependencySpec) ([]*model.IsDependency, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - - selectedPkg := isDependencySpec.Package - var dependentPkg *model.PkgSpec = nil - depMatchOnlyEmptyQualifiers := false - if isDependencySpec.DependencyPackage != nil { - dependentPkg = &model.PkgSpec{ - Type: isDependencySpec.DependencyPackage.Type, - Namespace: isDependencySpec.DependencyPackage.Namespace, - Name: isDependencySpec.DependencyPackage.Name, - // remove version, subpath and set qualifiers to empty list - Qualifiers: []*model.PackageQualifierSpec{}, - // setting to default value of false as package version is not checked for dependent packages - MatchOnlyEmptyQualifiers: &depMatchOnlyEmptyQualifiers, - } - } - - returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - "version.qualifier_list, isDependency, objPkgType.type, objPkgNamespace.namespace, objPkgName.name" - - queryValues := map[string]any{} - // query with pkgVersion - query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - "-[:subject]-(isDependency:IsDependency)-[:dependency]-(objPkgName:PkgName)<-[:PkgHasName]-(objPkgNamespace:PkgNamespace)<-[:PkgHasNamespace]" + - "-(objPkgType:PkgType)<-[:PkgHasType]-(objPkgRoot:Pkg)" - sb.WriteString(query) - - setPkgMatchValues(&sb, selectedPkg, false, &firstMatch, queryValues) - setPkgMatchValues(&sb, dependentPkg, true, &firstMatch, queryValues) - setIsDependencyValues(&sb, isDependencySpec, &firstMatch, queryValues) - - sb.WriteString(returnValue) - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedIsDependency := []*model.IsDependency{} - - for result.Next() { - pkgQualifiers := result.Record().Values[5] - subPath := result.Record().Values[4] - version := result.Record().Values[3] - nameString := result.Record().Values[2].(string) - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - nameString = result.Record().Values[9].(string) - namespaceString = result.Record().Values[8].(string) - typeString = result.Record().Values[7].(string) - - depPkg := generateModelPackage(typeString, namespaceString, nameString, nil, nil, nil) - - isDependencyNode := dbtype.Node{} - if result.Record().Values[6] != nil { - isDependencyNode = result.Record().Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("isDependency Node not found in neo4j") - } - - dependencyTypeEnum, err := convertDependencyTypeToEnum(isDependencyNode.Props[dependencyType].(string)) - if err != nil { - return nil, fmt.Errorf("convertDependencyTypeToEnum failed with error: %w", err) - } - - isDependency := &model.IsDependency{ - Package: pkg, - DependencyPackage: depPkg, - DependencyType: dependencyTypeEnum, - Origin: isDependencyNode.Props[origin].(string), - Collector: isDependencyNode.Props[collector].(string), - } - collectedIsDependency = append(collectedIsDependency, isDependency) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedIsDependency, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.IsDependency), nil -} - -func setIsDependencyValues(sb *strings.Builder, isDependencySpec *model.IsDependencySpec, firstMatch *bool, queryValues map[string]any) { - if isDependencySpec.DependencyType != nil { - matchProperties(sb, *firstMatch, "isDependency", dependencyType, "$"+dependencyType) - *firstMatch = false - queryValues[dependencyType] = isDependencySpec.DependencyType.String() - } - if isDependencySpec.Origin != nil { - matchProperties(sb, *firstMatch, "isDependency", origin, "$"+origin) - *firstMatch = false - queryValues[origin] = isDependencySpec.Origin - } - if isDependencySpec.Collector != nil { - matchProperties(sb, *firstMatch, "isDependency", collector, "$"+collector) - *firstMatch = false - queryValues[collector] = isDependencySpec.Collector - } -} - -// Ingest IngestDependencies - -func (c *neo4jClient) IngestDependencies(ctx context.Context, pkgs []*model.IDorPkgInput, depPkgs []*model.IDorPkgInput, dependencies []*model.IsDependencyInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestDependencies") -} - -// Ingest IsDependency -// note this has not been optimized to remove pkgVersion -> pkgName -func (c *neo4jClient) IngestDependency(ctx context.Context, pkg model.IDorPkgInput, depPkg model.IDorPkgInput, dependency model.IsDependencyInputSpec) (string, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) - defer session.Close() - // TODO: handle depPkgMatchType - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - // TODO: use generics here between PkgInputSpec and PkgSpec? - selectedPkgSpec := helper.ConvertPkgInputSpecToPkgSpec(pkg.PackageInput) - // Note: depPkgSpec only takes up to the pkgName as IsDependency does not allow for the attestation - // to be made at the pkgVersion level. Version range for the dependent package is defined as a property - // on IsDependency. - matchEmpty := false - depPkgSpec := model.PkgSpec{ - Type: &depPkg.PackageInput.Type, - Namespace: depPkg.PackageInput.Namespace, - Name: &depPkg.PackageInput.Name, - Version: nil, - Subpath: nil, - Qualifiers: nil, - MatchOnlyEmptyQualifiers: &matchEmpty, - } - - queryValues[dependencyType] = dependency.DependencyType.String() - queryValues[justification] = dependency.Justification - queryValues[origin] = dependency.Origin - queryValues[collector] = dependency.Collector - - returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - "version.qualifier_list, isDependency, objPkgType.type, objPkgNamespace.namespace, objPkgName.name" - - query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion), (objPkgRoot:Pkg)-[:PkgHasType]->(objPkgType:PkgType)-[:PkgHasNamespace]->(objPkgNamespace:PkgNamespace)" + - "-[:PkgHasName]->(objPkgName:PkgName)" - - sb.WriteString(query) - setPkgMatchValues(&sb, selectedPkgSpec, false, &firstMatch, queryValues) - setPkgMatchValues(&sb, &depPkgSpec, true, &firstMatch, queryValues) - - merge := "\nMERGE (version)<-[:subject]-(isDependency:IsDependency{dependencyType:$dependencyType,justification:$justification,origin:$origin,collector:$collector})" + - "-[:dependency]->(objPkgName)" - sb.WriteString(merge) - sb.WriteString(returnValue) - - result, err := session.WriteTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - // query returns a single record - record, err := result.Single() - if err != nil { - return nil, err - } - - pkgQualifiers := record.Values[5] - subPath := record.Values[4] - version := record.Values[3] - nameString := record.Values[2].(string) - namespaceString := record.Values[1].(string) - typeString := record.Values[0].(string) - - pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - nameString = record.Values[9].(string) - namespaceString = record.Values[8].(string) - typeString = record.Values[7].(string) - - depPkg := generateModelPackage(typeString, namespaceString, nameString, nil, nil, nil) - - isDependencyNode := dbtype.Node{} - if record.Values[6] != nil { - isDependencyNode = record.Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("isDependency Node not found in neo4j") - } - - dependencyTypeEnum, err := convertDependencyTypeToEnum(isDependencyNode.Props[dependencyType].(string)) - if err != nil { - return nil, fmt.Errorf("convertDependencyTypeToEnum failed with error: %w", err) - } - - isDependency := &model.IsDependency{ - Package: pkg, - DependencyPackage: depPkg, - DependencyType: dependencyTypeEnum, - Origin: isDependencyNode.Props[origin].(string), - Collector: isDependencyNode.Props[collector].(string), - } - - return isDependency, nil - }) - if err != nil { - return "", err - } - - return result.(*model.IsDependency).ID, nil -} - -func convertDependencyTypeToEnum(status string) (model.DependencyType, error) { - if status == model.DependencyTypeDirect.String() { - return model.DependencyTypeDirect, nil - } - if status == model.DependencyTypeIndirect.String() { - return model.DependencyTypeIndirect, nil - } - if status == model.DependencyTypeUnknown.String() { - return model.DependencyTypeUnknown, nil - } - return model.DependencyTypeUnknown, fmt.Errorf("failed to convert DependencyType to enum") -} diff --git a/pkg/assembler/backends/neo4j/isOccurrence.go b/pkg/assembler/backends/neo4j/isOccurrence.go deleted file mode 100644 index 9aaf51e054..0000000000 --- a/pkg/assembler/backends/neo4j/isOccurrence.go +++ /dev/null @@ -1,353 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - - "github.com/guacsec/guac/pkg/assembler/backends/helper" - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -// Query IsOccurrence - -func (c *neo4jClient) IsOccurrenceList(ctx context.Context, isOccurrenceSpec model.IsOccurrenceSpec, after *string, first *int) (*model.IsOccurrenceConnection, error) { - return nil, fmt.Errorf("not implemented: IsOccurrenceList") -} - -func (c *neo4jClient) IsOccurrence(ctx context.Context, isOccurrenceSpec *model.IsOccurrenceSpec) ([]*model.IsOccurrence, error) { - - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - queryAll := true - aggregateIsOccurrence := []*model.IsOccurrence{} - - if queryAll || (isOccurrenceSpec.Subject != nil && isOccurrenceSpec.Subject.Package != nil) { - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - "version.qualifier_list, isOccurrence, objArt.algorithm, objArt.digest" - - // query with pkgVersion - query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - "-[:subject]-(isOccurrence:IsOccurrence)-[:has_occurrence]-(objArt:Artifact)" - sb.WriteString(query) - - if isOccurrenceSpec.Subject != nil && isOccurrenceSpec.Subject.Package != nil { - setPkgMatchValues(&sb, isOccurrenceSpec.Subject.Package, false, &firstMatch, queryValues) - } - setArtifactMatchValues(&sb, isOccurrenceSpec.Artifact, true, &firstMatch, queryValues) - setIsOccurrenceValues(&sb, isOccurrenceSpec, &firstMatch, queryValues) - sb.WriteString(returnValue) - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedIsOccurrence := []*model.IsOccurrence{} - - for result.Next() { - pkgQualifiers := result.Record().Values[5] - subPath := result.Record().Values[4] - version := result.Record().Values[3] - nameString := result.Record().Values[2].(string) - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - algorithm := result.Record().Values[7].(string) - digest := result.Record().Values[8].(string) - artifact := generateModelArtifact(algorithm, digest) - - isOccurrenceNode := dbtype.Node{} - if result.Record().Values[6] != nil { - isOccurrenceNode = result.Record().Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("isOccurrence Node not found in neo4j") - } - - isOccurrence := generateModelIsOccurrence(pkg, artifact, isOccurrenceNode.Props[justification].(string), - isOccurrenceNode.Props[origin].(string), isOccurrenceNode.Props[collector].(string)) - - collectedIsOccurrence = append(collectedIsOccurrence, isOccurrence) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedIsOccurrence, nil - }) - if err != nil { - return nil, err - } - aggregateIsOccurrence = append(aggregateIsOccurrence, result.([]*model.IsOccurrence)...) - } - - if queryAll || (isOccurrenceSpec.Subject != nil && isOccurrenceSpec.Subject.Source != nil) { - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - query := "MATCH (root:Src)-[:SrcHasType]->(type:SrcType)-[:SrcHasNamespace]->(namespace:SrcNamespace)" + - "-[:SrcHasName]->(name:SrcName)-[:subject]-(isOccurrence:IsOccurrence)-[:has_occurrence]-(objArt:Artifact)" - sb.WriteString(query) - - if isOccurrenceSpec.Subject != nil && isOccurrenceSpec.Subject.Source != nil { - setSrcMatchValues(&sb, isOccurrenceSpec.Subject.Source, false, &firstMatch, queryValues) - } - setArtifactMatchValues(&sb, isOccurrenceSpec.Artifact, true, &firstMatch, queryValues) - setIsOccurrenceValues(&sb, isOccurrenceSpec, &firstMatch, queryValues) - sb.WriteString(" RETURN type.type, namespace.namespace, name.name, name.tag, name.commit, isOccurrence, objArt.algorithm, objArt.digest") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedIsOccurrence := []*model.IsOccurrence{} - - for result.Next() { - tag := result.Record().Values[3] - commit := result.Record().Values[4] - nameStr := result.Record().Values[2].(string) - namespaceStr := result.Record().Values[1].(string) - srcType := result.Record().Values[0].(string) - src := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - algorithm := result.Record().Values[6].(string) - digest := result.Record().Values[7].(string) - artifact := generateModelArtifact(algorithm, digest) - - isOccurrenceNode := dbtype.Node{} - if result.Record().Values[5] != nil { - isOccurrenceNode = result.Record().Values[5].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("isOccurrence Node not found in neo4j") - } - - isOccurrence := generateModelIsOccurrence(src, artifact, isOccurrenceNode.Props[justification].(string), - isOccurrenceNode.Props[origin].(string), isOccurrenceNode.Props[collector].(string)) - - collectedIsOccurrence = append(collectedIsOccurrence, isOccurrence) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedIsOccurrence, nil - }) - if err != nil { - return nil, err - } - aggregateIsOccurrence = append(aggregateIsOccurrence, result.([]*model.IsOccurrence)...) - } - return aggregateIsOccurrence, nil -} - -func setIsOccurrenceValues(sb *strings.Builder, isOccurrenceSpec *model.IsOccurrenceSpec, firstMatch *bool, queryValues map[string]any) { - if isOccurrenceSpec.Justification != nil { - matchProperties(sb, *firstMatch, "isOccurrence", justification, "$"+justification) - *firstMatch = false - queryValues[justification] = isOccurrenceSpec.Justification - } - if isOccurrenceSpec.Origin != nil { - matchProperties(sb, *firstMatch, "isOccurrence", origin, "$"+origin) - *firstMatch = false - queryValues[origin] = isOccurrenceSpec.Origin - } - if isOccurrenceSpec.Collector != nil { - matchProperties(sb, *firstMatch, "isOccurrence", collector, "$"+collector) - *firstMatch = false - queryValues[collector] = isOccurrenceSpec.Collector - } -} - -func generateModelIsOccurrence(subject model.PackageOrSource, artifact *model.Artifact, justification, origin, collector string) *model.IsOccurrence { - isOccurrence := model.IsOccurrence{ - Subject: subject, - Artifact: artifact, - Justification: justification, - Origin: origin, - Collector: collector, - } - return &isOccurrence -} - -// Ingest IngestOccurrences - -func (c *neo4jClient) IngestOccurrences(ctx context.Context, subjects model.PackageOrSourceInputs, artifacts []*model.IDorArtifactInput, occurrences []*model.IsOccurrenceInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented: IngestOccurrences") -} - -// Ingest IngestOccurrence - -func (c *neo4jClient) IngestOccurrence(ctx context.Context, subject model.PackageOrSourceInput, artifact model.IDorArtifactInput, occurrence model.IsOccurrenceInputSpec) (string, error) { - - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - occurrenceArt := helper.ConvertArtInputSpecToArtSpec(artifact.ArtifactInput) - - queryValues[justification] = occurrence.Justification - queryValues[origin] = occurrence.Origin - queryValues[collector] = occurrence.Collector - - if subject.Package != nil { - // TODO: use generics here between PkgInputSpec and PkgSpecs? - selectedPkgSpec := helper.ConvertPkgInputSpecToPkgSpec(subject.Package.PackageInput) - - query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion), (objArt:Artifact)" - - sb.WriteString(query) - setPkgMatchValues(&sb, selectedPkgSpec, false, &firstMatch, queryValues) - setArtifactMatchValues(&sb, occurrenceArt, true, &firstMatch, queryValues) - - merge := "\nMERGE (version)<-[:subject]-(isOccurrence:IsOccurrence{justification:$justification,origin:$origin,collector:$collector})" + - "-[:has_occurrence]->(objArt)" - sb.WriteString(merge) - returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - "version.qualifier_list, isOccurrence, objArt.algorithm, objArt.digest" - sb.WriteString(returnValue) - - result, err := session.WriteTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - // query returns a single record - record, err := result.Single() - if err != nil { - return nil, err - } - - pkgQualifiers := record.Values[5] - subPath := record.Values[4] - version := record.Values[3] - nameString := record.Values[2].(string) - namespaceString := record.Values[1].(string) - typeString := record.Values[0].(string) - - pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - algorithm := record.Values[7].(string) - digest := record.Values[8].(string) - artifact := generateModelArtifact(algorithm, digest) - - isOccurrenceNode := dbtype.Node{} - if record.Values[6] != nil { - isOccurrenceNode = record.Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("isOccurrence Node not found in neo4j") - } - - isOccurrence := generateModelIsOccurrence(pkg, artifact, isOccurrenceNode.Props[justification].(string), - isOccurrenceNode.Props[origin].(string), isOccurrenceNode.Props[collector].(string)) - - return isOccurrence, nil - }) - if err != nil { - return "", err - } - - return result.(*model.IsOccurrence).ID, nil - } else if subject.Source != nil { - // TODO: use generics here between SourceInputSpec and SourceSpec? - selectedSrcSpec := helper.ConvertSrcInputSpecToSrcSpec(subject.Source.SourceInput) - - returnValue := " RETURN type.type, namespace.namespace, name.name, name.tag, name.commit, isOccurrence, objArt.algorithm, objArt.digest" - - query := "MATCH (root:Src)-[:SrcHasType]->(type:SrcType)-[:SrcHasNamespace]->(namespace:SrcNamespace)" + - "-[:SrcHasName]->(name:SrcName), (objArt:Artifact)" - - sb.WriteString(query) - setSrcMatchValues(&sb, selectedSrcSpec, false, &firstMatch, queryValues) - setArtifactMatchValues(&sb, occurrenceArt, true, &firstMatch, queryValues) - - merge := "\nMERGE (name)<-[:subject]-(isOccurrence:IsOccurrence{justification:$justification,origin:$origin,collector:$collector})" + - "-[:has_occurrence]->(objArt)" - sb.WriteString(merge) - sb.WriteString(returnValue) - - result, err := session.WriteTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - // query returns a single record - record, err := result.Single() - if err != nil { - return nil, err - } - - tag := record.Values[3] - commit := record.Values[4] - nameStr := record.Values[2].(string) - namespaceStr := record.Values[1].(string) - srcType := record.Values[0].(string) - src := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - algorithm := record.Values[6].(string) - digest := record.Values[7].(string) - artifact := generateModelArtifact(algorithm, digest) - - isOccurrenceNode := dbtype.Node{} - if record.Values[5] != nil { - isOccurrenceNode = record.Values[5].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("isOccurrence Node not found in neo4j") - } - - isOccurrence := generateModelIsOccurrence(src, artifact, isOccurrenceNode.Props[justification].(string), - isOccurrenceNode.Props[origin].(string), isOccurrenceNode.Props[collector].(string)) - - return isOccurrence, nil - }) - if err != nil { - return "", err - } - - return result.(*model.IsOccurrence).ID, nil - - } else { - return "", gqlerror.Errorf("package or source not specified for IngestOccurrence") - } -} diff --git a/pkg/assembler/backends/neo4j/path.go b/pkg/assembler/backends/neo4j/path.go deleted file mode 100644 index e7ad366048..0000000000 --- a/pkg/assembler/backends/neo4j/path.go +++ /dev/null @@ -1,47 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" -) - -func (c *neo4jClient) Path(ctx context.Context, subject string, target string, maxPathLength int, usingOnly []model.Edge) ([]model.Node, error) { - panic(fmt.Errorf("not implemented: Path - path")) -} - -func (c *neo4jClient) Delete(ctx context.Context, node string) (bool, error) { - panic(fmt.Errorf("not implemented: Delete")) -} - -func (c *neo4jClient) NeighborsList(ctx context.Context, node string, usingOnly []model.Edge, after *string, first *int) (*model.NeighborConnection, error) { - return nil, fmt.Errorf("not implemented: NeighborsList") -} - -func (c *neo4jClient) Neighbors(ctx context.Context, node string, usingOnly []model.Edge) ([]model.Node, error) { - panic(fmt.Errorf("not implemented: Neighbors - neighbors")) -} - -func (c *neo4jClient) Node(ctx context.Context, node string) (model.Node, error) { - panic(fmt.Errorf("not implemented: Node - node")) -} - -func (c *neo4jClient) Nodes(ctx context.Context, nodes []string) ([]model.Node, error) { - panic(fmt.Errorf("not implemented: Nodes - nodes")) -} diff --git a/pkg/assembler/backends/neo4j/pkg.go b/pkg/assembler/backends/neo4j/pkg.go deleted file mode 100644 index 5bfb24a337..0000000000 --- a/pkg/assembler/backends/neo4j/pkg.go +++ /dev/null @@ -1,584 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "sort" - "strings" - - "github.com/guacsec/guac/pkg/assembler/backends/helper" - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" -) - -func (c *neo4jClient) PackagesList(ctx context.Context, pkgSpec model.PkgSpec, after *string, first *int) (*model.PackageConnection, error) { - return nil, fmt.Errorf("not implemented: PackagesList") -} - -func (c *neo4jClient) Packages(ctx context.Context, pkgSpec *model.PkgSpec) ([]*model.Package, error) { - // fields: [type namespaces namespaces.namespace namespaces.names namespaces.names.name namespaces.names.versions - // namespaces.names.versions.version namespaces.names.versions.qualifiers namespaces.names.versions.qualifiers.key - // namespaces.names.versions.qualifiers.value namespaces.names.versions.subpath] - fields := helper.GetPreloads(ctx) - - nameRequired := false - namespaceRequired := false - versionRequired := false - for _, f := range fields { - if f == namespaces { - namespaceRequired = true - } - if f == names { - nameRequired = true - } - if f == versions { - versionRequired = true - } - } - - if !namespaceRequired && !nameRequired && !versionRequired { - return c.packagesType(ctx, pkgSpec) - } else if namespaceRequired && !nameRequired && !versionRequired { - return c.packagesNamespace(ctx, pkgSpec) - } else if nameRequired && !versionRequired { - return c.packagesName(ctx, pkgSpec) - } - - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - sb.WriteString("MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)") - - setPkgMatchValues(&sb, pkgSpec, false, &firstMatch, queryValues) - - sb.WriteString(" RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, version.qualifier_list") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - pkgTypes := map[string]map[string]map[string][]*model.PackageVersion{} - - for result.Next() { - pkgQualifiers := []*model.PackageQualifier{} - if result.Record().Values[5] != nil { - pkgQualifiers = getCollectedPackageQualifiers(result.Record().Values[5].([]interface{})) - } - - subPathString := result.Record().Values[4].(string) - versionString := result.Record().Values[3].(string) - nameString := result.Record().Values[2].(string) - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - pkgVersion := &model.PackageVersion{ - Version: versionString, - Subpath: subPathString, - Qualifiers: pkgQualifiers, - } - - if pkgNamespaces, ok := pkgTypes[typeString]; ok { - if pkgNames, ok := pkgNamespaces[namespaceString]; ok { - pkgNames[nameString] = append(pkgNames[nameString], pkgVersion) - } else { - pkgNames := map[string][]*model.PackageVersion{} - pkgNames[nameString] = append(pkgNames[nameString], pkgVersion) - pkgNamespaces := map[string]map[string][]*model.PackageVersion{} - pkgNamespaces[namespaceString] = pkgNames - pkgTypes[typeString] = pkgNamespaces - } - } else { - pkgNames := map[string][]*model.PackageVersion{} - pkgNames[nameString] = append(pkgNames[nameString], pkgVersion) - pkgNamespaces := map[string]map[string][]*model.PackageVersion{} - pkgNamespaces[namespaceString] = pkgNames - pkgTypes[typeString] = pkgNamespaces - } - } - if err = result.Err(); err != nil { - return nil, err - } - - packages := []*model.Package{} - for pkgType, pkgNamespaces := range pkgTypes { - collectedPkgNamespaces := []*model.PackageNamespace{} - for namespace, pkgNames := range pkgNamespaces { - collectedPkgNames := []*model.PackageName{} - for name, versions := range pkgNames { - pkgName := &model.PackageName{ - Name: name, - Versions: versions, - } - collectedPkgNames = append(collectedPkgNames, pkgName) - } - pkgNamespace := &model.PackageNamespace{ - Namespace: namespace, - Names: collectedPkgNames, - } - collectedPkgNamespaces = append(collectedPkgNamespaces, pkgNamespace) - } - collectedPackage := &model.Package{ - Type: pkgType, - Namespaces: collectedPkgNamespaces, - } - packages = append(packages, collectedPackage) - } - - return packages, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.Package), nil -} - -func (c *neo4jClient) packagesType(ctx context.Context, pkgSpec *model.PkgSpec) ([]*model.Package, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - sb.WriteString("MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)") - - if pkgSpec.Type != nil { - - matchProperties(&sb, firstMatch, "type", "type", "$pkgType") - queryValues["pkgType"] = pkgSpec.Type - } - - sb.WriteString(" RETURN type.type") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - packages := []*model.Package{} - for result.Next() { - collectedPackage := &model.Package{ - Type: result.Record().Values[0].(string), - Namespaces: []*model.PackageNamespace{}, - } - packages = append(packages, collectedPackage) - } - if err = result.Err(); err != nil { - return nil, err - } - - return packages, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.Package), nil -} - -func (c *neo4jClient) packagesNamespace(ctx context.Context, pkgSpec *model.PkgSpec) ([]*model.Package, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - sb.WriteString("MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)") - - if pkgSpec.Type != nil { - - matchProperties(&sb, firstMatch, "type", "type", "$pkgType") - firstMatch = false - queryValues["pkgType"] = pkgSpec.Type - } - if pkgSpec.Namespace != nil { - - matchProperties(&sb, firstMatch, "namespace", "namespace", "$pkgNamespace") - queryValues["pkgNamespace"] = pkgSpec.Namespace - } - - sb.WriteString(" RETURN type.type, namespace.namespace") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - pkgTypes := map[string][]*model.PackageNamespace{} - - for result.Next() { - - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - pkgNamespace := &model.PackageNamespace{ - Namespace: namespaceString, - Names: []*model.PackageName{}, - } - pkgTypes[typeString] = append(pkgTypes[typeString], pkgNamespace) - } - if err = result.Err(); err != nil { - return nil, err - } - - packages := []*model.Package{} - for pkgType, namespaces := range pkgTypes { - collectedPackage := &model.Package{ - Type: pkgType, - Namespaces: namespaces, - } - packages = append(packages, collectedPackage) - } - - return packages, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.Package), nil -} - -func (c *neo4jClient) packagesName(ctx context.Context, pkgSpec *model.PkgSpec) ([]*model.Package, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - sb.WriteString("MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)-[:PkgHasName]->(name:PkgName)") - if pkgSpec.Type != nil { - - matchProperties(&sb, firstMatch, "type", "type", "$pkgType") - firstMatch = false - queryValues["pkgType"] = pkgSpec.Type - } - if pkgSpec.Namespace != nil { - - matchProperties(&sb, firstMatch, "namespace", "namespace", "$pkgNamespace") - firstMatch = false - queryValues["pkgNamespace"] = pkgSpec.Namespace - } - if pkgSpec.Name != nil { - - matchProperties(&sb, firstMatch, "name", "name", "$pkgName") - queryValues["pkgName"] = pkgSpec.Name - } - - sb.WriteString(" RETURN type.type, namespace.namespace, name.name") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - pkgTypes := map[string]map[string][]*model.PackageName{} - - for result.Next() { - - nameString := result.Record().Values[2].(string) - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - pkgName := &model.PackageName{ - Name: nameString, - Versions: []*model.PackageVersion{}, - } - - if pkgNamespace, ok := pkgTypes[typeString]; ok { - pkgNamespace[namespaceString] = append(pkgNamespace[namespaceString], pkgName) - } else { - pkgNamespaces := map[string][]*model.PackageName{} - pkgNamespaces[namespaceString] = append(pkgNamespaces[namespaceString], pkgName) - pkgTypes[typeString] = pkgNamespaces - } - } - if err = result.Err(); err != nil { - return nil, err - } - - packages := []*model.Package{} - for pkgType, pkgNamespaces := range pkgTypes { - collectedPkgNamespaces := []*model.PackageNamespace{} - for namespace, pkgNames := range pkgNamespaces { - pkgNamespace := &model.PackageNamespace{ - Namespace: namespace, - Names: pkgNames, - } - collectedPkgNamespaces = append(collectedPkgNamespaces, pkgNamespace) - } - collectedPackage := &model.Package{ - Type: pkgType, - Namespaces: collectedPkgNamespaces, - } - packages = append(packages, collectedPackage) - } - - return packages, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.Package), nil -} - -func removeInvalidCharFromProperty(key string) string { - // neo4j does not accept "." in its properties. If the qualifier contains a "." that must - // be replaced by an "-" - return strings.ReplaceAll(key, ".", "_") -} - -func (c *neo4jClient) IngestPackages(ctx context.Context, pkgs []*model.IDorPkgInput) ([]*model.PackageIDs, error) { - return []*model.PackageIDs{}, fmt.Errorf("not implemented: IngestPackages") -} - -func (c *neo4jClient) IngestPackage(ctx context.Context, pkg model.IDorPkgInput) (*model.PackageIDs, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) - defer session.Close() - - values := map[string]any{} - values["pkgType"] = pkg.PackageInput.Type - values["name"] = pkg.PackageInput.Name - if pkg.PackageInput.Namespace != nil { - values["namespace"] = *pkg.PackageInput.Namespace - } else { - values["namespace"] = "" - } - if pkg.PackageInput.Version != nil { - values["version"] = *pkg.PackageInput.Version - } else { - values["version"] = "" - } - if pkg.PackageInput.Subpath != nil { - values["subpath"] = *pkg.PackageInput.Subpath - } else { - values["subpath"] = "" - } - - // To ensure consistency, always sort the qualifiers by key - qualifiersMap := map[string]string{} - keys := []string{} - for _, kv := range pkg.PackageInput.Qualifiers { - qualifiersMap[kv.Key] = kv.Value - keys = append(keys, kv.Key) - } - sort.Strings(keys) - qualifiers := []string{} - for _, k := range keys { - qualifiers = append(qualifiers, k, qualifiersMap[k]) - } - values["qualifier"] = qualifiers - - result, err := session.WriteTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - query := `MERGE (root:Pkg) -MERGE (root) -[:PkgHasType]-> (type:PkgType{type:$pkgType}) -MERGE (type) -[:PkgHasNamespace]-> (ns:PkgNamespace{namespace:$namespace}) -MERGE (ns) -[:PkgHasName]-> (name:PkgName{name:$name}) -MERGE (name) -[:PkgHasVersion]-> (version:PkgVersion{version:$version,subpath:$subpath,qualifier_list:$qualifier}) -RETURN type.type, ns.namespace, name.name, version.version, version.subpath, version.qualifier_list` - result, err := tx.Run(query, values) - if err != nil { - return nil, err - } - - // query returns a single record - record, err := result.Single() - if err != nil { - return nil, err - } - - qualifiersList := record.Values[5] - subPath := record.Values[4] - version := record.Values[3] - nameStr := record.Values[2].(string) - namespaceStr := record.Values[1].(string) - pkgType := record.Values[0].(string) - - pkg := generateModelPackage(pkgType, namespaceStr, nameStr, version, subPath, qualifiersList) - return pkg, nil - }) - if err != nil { - return nil, err - } - - // TODO: this need to return all IDs for type, namespace, name and version - return &model.PackageIDs{ - PackageVersionID: result.(*model.Package).ID, - }, nil -} - -func getCollectedPackageQualifiers(qualifierList []interface{}) []*model.PackageQualifier { - qualifiers := []*model.PackageQualifier{} - for i := range qualifierList { - if i%2 == 0 { - qualifier := &model.PackageQualifier{ - Key: qualifierList[i].(string), - Value: qualifierList[i+1].(string), - } - qualifiers = append(qualifiers, qualifier) - } - } - return qualifiers -} - -func getQualifiers(qualifiersSpec []*model.PackageQualifierSpec) []string { - qualifiersMap := map[string]string{} - keys := []string{} - for _, kv := range qualifiersSpec { - key := removeInvalidCharFromProperty(kv.Key) - qualifiersMap[key] = *kv.Value - keys = append(keys, key) - } - sort.Strings(keys) - qualifiers := []string{} - for _, k := range keys { - qualifiers = append(qualifiers, k, qualifiersMap[k]) - } - return qualifiers -} - -func setPkgMatchValues(sb *strings.Builder, pkg *model.PkgSpec, objectPkg bool, firstMatch *bool, queryValues map[string]any) { - if pkg != nil { - if pkg.Type != nil { - if !objectPkg { - matchProperties(sb, *firstMatch, "type", "type", "$pkgType") - queryValues["pkgType"] = pkg.Type - } else { - matchProperties(sb, *firstMatch, "objPkgType", "type", "$objPkgType") - queryValues["objPkgType"] = pkg.Type - } - *firstMatch = false - } - if pkg.Namespace != nil { - if !objectPkg { - matchProperties(sb, *firstMatch, "namespace", "namespace", "$pkgNamespace") - queryValues["pkgNamespace"] = pkg.Namespace - } else { - matchProperties(sb, *firstMatch, "objPkgNamespace", "namespace", "$objPkgNamespace") - queryValues["objPkgNamespace"] = pkg.Namespace - } - *firstMatch = false - } - if pkg.Name != nil { - if !objectPkg { - matchProperties(sb, *firstMatch, "name", "name", "$pkgName") - queryValues["pkgName"] = pkg.Name - } else { - matchProperties(sb, *firstMatch, "objPkgName", "name", "$objPkgName") - queryValues["objPkgName"] = pkg.Name - } - *firstMatch = false - } - if pkg.Version != nil { - if !objectPkg { - matchProperties(sb, *firstMatch, "version", "version", "$pkgVersion") - queryValues["pkgVersion"] = pkg.Version - } else { - matchProperties(sb, *firstMatch, "objPkgVersion", "version", "$objPkgVersion") - queryValues["objPkgVersion"] = pkg.Version - } - *firstMatch = false - } - - if pkg.Subpath != nil { - if !objectPkg { - matchProperties(sb, *firstMatch, "version", "subpath", "$pkgSubpath") - queryValues["pkgSubpath"] = pkg.Subpath - } else { - matchProperties(sb, *firstMatch, "objPkgVersion", "subpath", "$objPkgSubpath") - queryValues["objPkgSubpath"] = pkg.Subpath - } - *firstMatch = false - } - - if !*pkg.MatchOnlyEmptyQualifiers { - if len(pkg.Qualifiers) > 0 { - if !objectPkg { - qualifiers := getQualifiers(pkg.Qualifiers) - matchProperties(sb, *firstMatch, "version", "qualifier_list", "$pkgQualifierList") - queryValues["pkgQualifierList"] = qualifiers - } else { - qualifiers := getQualifiers(pkg.Qualifiers) - matchProperties(sb, *firstMatch, "objPkgVersion", "qualifier_list", "$objPkgQualifierList") - queryValues["objPkgQualifierList"] = qualifiers - } - *firstMatch = false - } - } else { - if !objectPkg { - matchProperties(sb, *firstMatch, "version", "qualifier_list", "$pkgQualifierList") - queryValues["pkgQualifierList"] = []string{} - } else { - matchProperties(sb, *firstMatch, "objPkgVersion", "qualifier_list", "$objPkgQualifierList") - queryValues["objPkgQualifierList"] = []string{} - } - *firstMatch = false - } - } -} - -func generateModelPackage(pkgType, namespaceStr, nameStr string, versionValue, subPathValue, qualifiersValue interface{}) *model.Package { - var version *model.PackageVersion = nil - if versionValue != nil && subPathValue != nil && qualifiersValue != nil { - qualifiersList := qualifiersValue.([]interface{}) - subPathString := subPathValue.(string) - versionString := versionValue.(string) - qualifiers := getCollectedPackageQualifiers(qualifiersList) - version = &model.PackageVersion{ - Version: versionString, - Subpath: subPathString, - Qualifiers: qualifiers, - } - } - - versions := []*model.PackageVersion{} - if version != nil { - versions = append(versions, version) - } - name := &model.PackageName{ - Name: nameStr, - Versions: versions, - } - namespace := &model.PackageNamespace{ - Namespace: namespaceStr, - Names: []*model.PackageName{name}, - } - pkg := model.Package{ - Type: pkgType, - Namespaces: []*model.PackageNamespace{namespace}, - } - return &pkg -} diff --git a/pkg/assembler/backends/neo4j/pkgEqual.go b/pkg/assembler/backends/neo4j/pkgEqual.go deleted file mode 100644 index 2381f859bf..0000000000 --- a/pkg/assembler/backends/neo4j/pkgEqual.go +++ /dev/null @@ -1,267 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - - "github.com/guacsec/guac/pkg/assembler/backends/helper" - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -// Query PkgEqual - -func (c *neo4jClient) PkgEqualList(ctx context.Context, pkgEqualSpec model.PkgEqualSpec, after *string, first *int) (*model.PkgEqualConnection, error) { - return nil, fmt.Errorf("not implemented: PkgEqualList") -} - -func (c *neo4jClient) PkgEqual(ctx context.Context, pkgEqualSpec *model.PkgEqualSpec) ([]*model.PkgEqual, error) { - - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var selectedPkg *model.PkgSpec = nil - var dependentPkg *model.PkgSpec = nil - if pkgEqualSpec.Packages != nil && len(pkgEqualSpec.Packages) != 0 { - if len(pkgEqualSpec.Packages) == 1 { - selectedPkg = pkgEqualSpec.Packages[0] - } else { - selectedPkg = pkgEqualSpec.Packages[0] - dependentPkg = pkgEqualSpec.Packages[1] - } - } - - queryValues := map[string]any{} - - // query with for subject and object package - queryPkgEqual(&sb, selectedPkg, dependentPkg, pkgEqualSpec, false, queryValues) - - if len(pkgEqualSpec.Packages) > 0 { - // query with reverse order for subject and object package - queryPkgEqual(&sb, dependentPkg, selectedPkg, pkgEqualSpec, true, queryValues) - } - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - collectedPkgEqual := []*model.PkgEqual{} - - for result.Next() { - - pkgQualifiers := result.Record().Values[5] - subPath := result.Record().Values[4] - version := result.Record().Values[3] - nameString := result.Record().Values[2].(string) - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - pkgQualifiers = result.Record().Values[12] - subPath = result.Record().Values[11] - version = result.Record().Values[10] - nameString = result.Record().Values[9].(string) - namespaceString = result.Record().Values[8].(string) - typeString = result.Record().Values[7].(string) - - depPkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - pkgEqualNode := dbtype.Node{} - if result.Record().Values[6] != nil { - pkgEqualNode = result.Record().Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("pkgEqual Node not found in neo4j") - } - - pkgEqual := &model.PkgEqual{ - Packages: []*model.Package{pkg, depPkg}, - Justification: pkgEqualNode.Props[justification].(string), - Origin: pkgEqualNode.Props[origin].(string), - Collector: pkgEqualNode.Props[collector].(string), - } - collectedPkgEqual = append(collectedPkgEqual, pkgEqual) - } - if err = result.Err(); err != nil { - return nil, err - } - - return collectedPkgEqual, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.PkgEqual), nil -} - -func queryPkgEqual(sb *strings.Builder, selectedPkg *model.PkgSpec, dependentPkg *model.PkgSpec, pkgEqualSpec *model.PkgEqualSpec, addInitialUnion bool, - queryValues map[string]any) { - - returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - "version.qualifier_list, pkgEqual, objPkgType.type, objPkgNamespace.namespace, objPkgName.name, " + - "objPkgVersion.version, objPkgVersion.subpath, objPkgVersion.qualifier_list" - - if addInitialUnion { - sb.WriteString("\nUNION") - sb.WriteString("\n") - } - // query with selectedPkg at pkgVersion and dependentPkg at pkgVersion - query := "\nMATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" + - "-[:subject]-(pkgEqual:PkgEqual)-[:pkg_certification]-(objPkgVersion:PkgVersion)" + - "\nWITH *" + - "\nMATCH (objPkgVersion)<-[:PkgHasVersion]-(objPkgName:PkgName)<-[:PkgHasName]" + - "-(objPkgNamespace:PkgNamespace)<-[:PkgHasNamespace]" + - "-(objPkgType:PkgType)<-[:PkgHasType]-(objPkgRoot:Pkg)" - sb.WriteString(query) - - firstMatch := true - setPkgMatchValues(sb, selectedPkg, false, &firstMatch, queryValues) - setPkgMatchValues(sb, dependentPkg, true, &firstMatch, queryValues) - setPkgEqualValues(sb, pkgEqualSpec, &firstMatch, queryValues) - - sb.WriteString(returnValue) -} - -func setPkgEqualValues(sb *strings.Builder, pkgEqualSpec *model.PkgEqualSpec, firstMatch *bool, queryValues map[string]any) { - if pkgEqualSpec.Justification != nil { - - matchProperties(sb, *firstMatch, "pkgEqual", justification, "$"+justification) - *firstMatch = false - queryValues[justification] = pkgEqualSpec.Justification - } - if pkgEqualSpec.Origin != nil { - - matchProperties(sb, *firstMatch, "pkgEqual", origin, "$"+origin) - *firstMatch = false - queryValues[origin] = pkgEqualSpec.Origin - } - if pkgEqualSpec.Collector != nil { - - matchProperties(sb, *firstMatch, "pkgEqual", collector, "$"+collector) - *firstMatch = false - queryValues[collector] = pkgEqualSpec.Collector - } -} - -// Ingest PkgEqual - -func (c *neo4jClient) IngestPkgEqual(ctx context.Context, pkg model.IDorPkgInput, depPkg model.IDorPkgInput, pkgEqual model.PkgEqualInputSpec) (string, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) - defer session.Close() - - var sb strings.Builder - queryValues := map[string]any{} - - // TODO: use generics here between PkgInputSpec and PkgSpec? - selectedPkgSpec := helper.ConvertPkgInputSpecToPkgSpec(pkg.PackageInput) - depPkgSpec := helper.ConvertPkgInputSpecToPkgSpec(depPkg.PackageInput) - - queryValues[justification] = pkgEqual.Justification - queryValues[origin] = pkgEqual.Origin - queryValues[collector] = pkgEqual.Collector - - query := "MATCH (root:Pkg)-[:PkgHasType]->(type:PkgType)-[:PkgHasNamespace]->(namespace:PkgNamespace)" + - "-[:PkgHasName]->(name:PkgName)-[:PkgHasVersion]->(version:PkgVersion)" - - firstMatch := true - sb.WriteString(query) - setPkgMatchValues(&sb, selectedPkgSpec, false, &firstMatch, queryValues) - - query = "\nMATCH (objPkgRoot:Pkg)-[:PkgHasType]->(objPkgType:PkgType)-[:PkgHasNamespace]->(objPkgNamespace:PkgNamespace)" + - "-[:PkgHasName]->(objPkgName:PkgName)-[:PkgHasVersion]->(objPkgVersion:PkgVersion)" - - firstMatch = true - sb.WriteString(query) - setPkgMatchValues(&sb, depPkgSpec, true, &firstMatch, queryValues) - - merge := "\nMERGE (version)<-[:subject]-(pkgEqual:PkgEqual{justification:$justification,origin:$origin,collector:$collector})" + - "-[:pkg_certification]->(objPkgVersion)" - - sb.WriteString(merge) - - returnValue := " RETURN type.type, namespace.namespace, name.name, version.version, version.subpath, " + - "version.qualifier_list, pkgEqual, objPkgType.type, objPkgNamespace.namespace, objPkgName.name, " + - "objPkgVersion.version, objPkgVersion.subpath, objPkgVersion.qualifier_list" - - sb.WriteString(returnValue) - - result, err := session.WriteTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - // query returns a single record - record, err := result.Single() - if err != nil { - return nil, err - } - - pkgQualifiers := record.Values[5] - subPath := record.Values[4] - version := record.Values[3] - nameString := record.Values[2].(string) - namespaceString := record.Values[1].(string) - typeString := record.Values[0].(string) - - pkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - pkgQualifiers = record.Values[12] - subPath = record.Values[11] - version = record.Values[10] - nameString = record.Values[9].(string) - namespaceString = record.Values[8].(string) - typeString = record.Values[7].(string) - - depPkg := generateModelPackage(typeString, namespaceString, nameString, version, subPath, pkgQualifiers) - - pkgEqualNode := dbtype.Node{} - if record.Values[6] != nil { - pkgEqualNode = record.Values[6].(dbtype.Node) - } else { - return nil, gqlerror.Errorf("pkgEqual Node not found in neo4j") - } - - pkgEqual := &model.PkgEqual{ - Packages: []*model.Package{pkg, depPkg}, - Justification: pkgEqualNode.Props[justification].(string), - Origin: pkgEqualNode.Props[origin].(string), - Collector: pkgEqualNode.Props[collector].(string), - } - - return pkgEqual, nil - }) - if err != nil { - return "", err - } - return result.(*model.PkgEqual).ID, nil -} - -func (c *neo4jClient) IngestPkgEquals(ctx context.Context, pkgs []*model.IDorPkgInput, otherPackages []*model.IDorPkgInput, pkgEquals []*model.PkgEqualInputSpec) ([]string, error) { - return nil, fmt.Errorf("not implemented - IngestPkgEquals") -} diff --git a/pkg/assembler/backends/neo4j/search.go b/pkg/assembler/backends/neo4j/search.go deleted file mode 100644 index d73853e9b0..0000000000 --- a/pkg/assembler/backends/neo4j/search.go +++ /dev/null @@ -1,55 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" -) - -func (c *neo4jClient) FindSoftware(ctx context.Context, searchText string) ([]model.PackageSourceOrArtifact, error) { - return []model.PackageSourceOrArtifact{}, fmt.Errorf("not implemented: FindSoftware") -} - -func (c *neo4jClient) FindSoftwareList(ctx context.Context, searchText string, after *string, first *int) (*model.FindSoftwareConnection, error) { - return nil, fmt.Errorf("not implemented: FindSoftwareList") -} - -func (c *neo4jClient) QueryPackagesListForScan(ctx context.Context, pkgIDs []string, after *string, first *int) (*model.PackageConnection, error) { - return nil, fmt.Errorf("not implemented: QueryPackagesListForScan") -} - -func (c *neo4jClient) FindPackagesThatNeedScanning(ctx context.Context, queryType model.QueryType, lastScan *int) ([]string, error) { - return nil, fmt.Errorf("not implemented: FindPackagesThatNeedScanning") -} - -func (c *neo4jClient) BatchQueryPkgIDCertifyVuln(ctx context.Context, pkgIDs []string) ([]*model.CertifyVuln, error) { - return nil, fmt.Errorf("not implemented: BatchQueryPkgIDCertifyVuln") -} - -func (c *neo4jClient) BatchQueryPkgIDCertifyLegal(ctx context.Context, pkgIDs []string) ([]*model.CertifyLegal, error) { - return nil, fmt.Errorf("not implemented: BatchQueryPkgIDCertifyLegal") -} - -func (c *neo4jClient) BatchQuerySubjectPkgDependency(ctx context.Context, pkgIDs []string) ([]*model.IsDependency, error) { - return nil, fmt.Errorf("not implemented: BatchQuerySubjectPkgDependency") -} - -func (c *neo4jClient) BatchQueryDepPkgDependency(ctx context.Context, pkgIDs []string) ([]*model.IsDependency, error) { - return nil, fmt.Errorf("not implemented: BatchQueryDepPkgDependency") -} diff --git a/pkg/assembler/backends/neo4j/src.go b/pkg/assembler/backends/neo4j/src.go deleted file mode 100644 index d42f65a122..0000000000 --- a/pkg/assembler/backends/neo4j/src.go +++ /dev/null @@ -1,401 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - "strings" - - "github.com/guacsec/guac/pkg/assembler/backends/helper" - "github.com/guacsec/guac/pkg/assembler/graphql/model" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/vektah/gqlparser/v2/gqlerror" -) - -func (c *neo4jClient) SourcesList(ctx context.Context, sourceSpec model.SourceSpec, after *string, first *int) (*model.SourceConnection, error) { - return nil, fmt.Errorf("not implemented: SourcesList") -} - -func (c *neo4jClient) Sources(ctx context.Context, sourceSpec *model.SourceSpec) ([]*model.Source, error) { - - // fields: [type namespaces namespaces.namespace namespaces.names namespaces.names.name namespaces.names.tag namespaces.names.commit] - fields := helper.GetPreloads(ctx) - - nameRequired := false - namespaceRequired := false - for _, f := range fields { - if f == namespaces { - namespaceRequired = true - } - if f == names { - nameRequired = true - } - } - - if !namespaceRequired && !nameRequired { - return c.sourcesType(ctx, sourceSpec) - } else if namespaceRequired && !nameRequired { - return c.sourcesNamespace(ctx, sourceSpec) - } - - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - if sourceSpec.Commit != nil && sourceSpec.Tag != nil { - if *sourceSpec.Commit != "" && *sourceSpec.Tag != "" { - return nil, gqlerror.Errorf("Passing both commit and tag selectors is an error") - } - } - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - - sb.WriteString("MATCH (root:Src)-[:SrcHasType]->(type:SrcType)-[:SrcHasNamespace]->(namespace:SrcNamespace)-[:SrcHasName]->(name:SrcName)") - - setSrcMatchValues(&sb, sourceSpec, false, &firstMatch, queryValues) - - sb.WriteString(" RETURN type.type, namespace.namespace, name.name, name.tag, name.commit") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - srcTypes := map[string]map[string][]*model.SourceName{} - for result.Next() { - - commitString := result.Record().Values[4].(string) - tagString := result.Record().Values[3].(string) - nameString := result.Record().Values[2].(string) - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - srcName := &model.SourceName{ - Name: nameString, - Tag: &tagString, - Commit: &commitString, - } - if srcNamespaces, ok := srcTypes[typeString]; ok { - srcNamespaces[namespaceString] = append(srcNamespaces[namespaceString], srcName) - } else { - srcNamespaces := map[string][]*model.SourceName{} - srcNamespaces[namespaceString] = append(srcNamespaces[namespaceString], srcName) - srcTypes[typeString] = srcNamespaces - } - } - if err = result.Err(); err != nil { - return nil, err - } - - sources := []*model.Source{} - for srcType, namespaces := range srcTypes { - sourceNamespaces := []*model.SourceNamespace{} - for namespace, sourceNames := range namespaces { - srcNamespace := &model.SourceNamespace{ - Namespace: namespace, - Names: sourceNames, - } - sourceNamespaces = append(sourceNamespaces, srcNamespace) - } - - source := &model.Source{ - Type: srcType, - Namespaces: sourceNamespaces, - } - sources = append(sources, source) - } - - return sources, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.Source), nil -} - -func (c *neo4jClient) sourcesType(ctx context.Context, sourceSpec *model.SourceSpec) ([]*model.Source, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - sb.WriteString("MATCH (root:Src)-[:SrcHasType]->(type:SrcType)") - - if sourceSpec.Type != nil { - - matchProperties(&sb, firstMatch, "type", "type", "$srcType") - queryValues["srcType"] = sourceSpec.Type - } - - sb.WriteString(" RETURN type.type") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - sources := []*model.Source{} - for result.Next() { - - source := &model.Source{ - Type: result.Record().Values[0].(string), - Namespaces: []*model.SourceNamespace{}, - } - - sources = append(sources, source) - } - if err = result.Err(); err != nil { - return nil, err - } - - return sources, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.Source), nil -} - -func (c *neo4jClient) sourcesNamespace(ctx context.Context, sourceSpec *model.SourceSpec) ([]*model.Source, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close() - - var sb strings.Builder - var firstMatch bool = true - queryValues := map[string]any{} - sb.WriteString("MATCH (root:Src)-[:SrcHasType]->(type:SrcType)-[:SrcHasNamespace]->(namespace:SrcNamespace)") - - if sourceSpec.Type != nil { - - matchProperties(&sb, firstMatch, "type", "type", "$srcType") - firstMatch = false - queryValues["srcType"] = sourceSpec.Type - } - if sourceSpec.Namespace != nil { - - matchProperties(&sb, firstMatch, "namespace", "namespace", "$srcNamespace") - queryValues["srcNamespace"] = sourceSpec.Namespace - } - sb.WriteString(" RETURN type.type, namespace.namespace") - - result, err := session.ReadTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - - result, err := tx.Run(sb.String(), queryValues) - if err != nil { - return nil, err - } - - srcTypes := map[string][]*model.SourceNamespace{} - for result.Next() { - - namespaceString := result.Record().Values[1].(string) - typeString := result.Record().Values[0].(string) - - srcNamespace := &model.SourceNamespace{ - Namespace: namespaceString, - Names: []*model.SourceName{}, - } - srcTypes[typeString] = append(srcTypes[typeString], srcNamespace) - - } - if err = result.Err(); err != nil { - return nil, err - } - - sources := []*model.Source{} - for srcType, namespaces := range srcTypes { - source := &model.Source{ - Type: srcType, - Namespaces: namespaces, - } - sources = append(sources, source) - } - - return sources, nil - }) - if err != nil { - return nil, err - } - - return result.([]*model.Source), nil -} - -func (c *neo4jClient) IngestSources(ctx context.Context, sources []*model.IDorSourceInput) ([]*model.SourceIDs, error) { - return []*model.SourceIDs{}, fmt.Errorf("not implemented: IngestSources") -} - -func (c *neo4jClient) IngestSource(ctx context.Context, source model.IDorSourceInput) (*model.SourceIDs, error) { - session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) - defer session.Close() - - values := map[string]any{} - values["sourceType"] = source.SourceInput.Type - values["namespace"] = source.SourceInput.Namespace - values["name"] = source.SourceInput.Name - - if source.SourceInput.Commit != nil && source.SourceInput.Tag != nil { - if *source.SourceInput.Commit != "" && *source.SourceInput.Tag != "" { - return nil, gqlerror.Errorf("Passing both commit and tag selectors is an error") - } - } - - if source.SourceInput.Commit != nil { - values["commit"] = *source.SourceInput.Commit - } else { - values["commit"] = "" - } - - if source.SourceInput.Tag != nil { - values["tag"] = *source.SourceInput.Tag - } else { - values["tag"] = "" - } - - result, err := session.WriteTransaction( - func(tx neo4j.Transaction) (interface{}, error) { - query := `MERGE (root:Src) -MERGE (root) -[:SrcHasType]-> (type:SrcType{type:$sourceType}) -MERGE (type) -[:SrcHasNamespace]-> (ns:SrcNamespace{namespace:$namespace}) -MERGE (ns) -[:SrcHasName]-> (name:SrcName{name:$name,commit:$commit,tag:$tag}) -RETURN type.type, ns.namespace, name.name, name.commit, name.tag` - result, err := tx.Run(query, values) - if err != nil { - return nil, err - } - - // query returns a single record - record, err := result.Single() - if err != nil { - return nil, err - } - - tag := record.Values[4] - commit := record.Values[3] - nameStr := record.Values[2].(string) - namespaceStr := record.Values[1].(string) - srcType := record.Values[0].(string) - - src := generateModelSource(srcType, namespaceStr, nameStr, commit, tag) - - return src, nil - }) - if err != nil { - return nil, err - } - - // TODO: return ID for type, namespace and name - return &model.SourceIDs{ - SourceNameID: result.(*model.Source).ID, - }, nil -} - -func setSrcMatchValues(sb *strings.Builder, src *model.SourceSpec, objectSrc bool, firstMatch *bool, queryValues map[string]any) { - if src != nil { - if src.Type != nil { - if !objectSrc { - matchProperties(sb, *firstMatch, "type", "type", "$srcType") - queryValues["srcType"] = src.Type - } else { - matchProperties(sb, *firstMatch, "objSrcType", "type", "$objSrcType") - queryValues["objSrcType"] = src.Type - } - *firstMatch = false - } - if src.Namespace != nil { - if !objectSrc { - matchProperties(sb, *firstMatch, "namespace", "namespace", "$srcNamespace") - queryValues["srcNamespace"] = src.Namespace - } else { - matchProperties(sb, *firstMatch, "objSrcNamespace", "namespace", "$objSrcNamespace") - queryValues["objSrcNamespace"] = src.Namespace - } - *firstMatch = false - } - if src.Name != nil { - if !objectSrc { - matchProperties(sb, *firstMatch, "name", "name", "$srcName") - queryValues["srcName"] = src.Name - } else { - matchProperties(sb, *firstMatch, "objSrcName", "name", "$objSrcName") - queryValues["objSrcName"] = src.Name - } - *firstMatch = false - } - - if src.Tag != nil { - if !objectSrc { - matchProperties(sb, *firstMatch, "name", "tag", "$srcTag") - queryValues["srcTag"] = src.Tag - } else { - matchProperties(sb, *firstMatch, "objSrcName", "tag", "$objSrcTag") - queryValues["objSrcTag"] = src.Tag - } - *firstMatch = false - } - - if src.Commit != nil { - if !objectSrc { - matchProperties(sb, *firstMatch, "name", "commit", "$srcCommit") - queryValues["srcCommit"] = src.Commit - } else { - matchProperties(sb, *firstMatch, "objSrcName", "commit", "$objSrcCommit") - queryValues["objSrcCommit"] = src.Commit - } - *firstMatch = false - } - } -} - -func generateModelSource(srcType, namespaceStr, nameStr string, commitValue, tagValue interface{}) *model.Source { - tag := (*string)(nil) - if tagValue != nil { - tagStr := tagValue.(string) - tag = &tagStr - } - commit := (*string)(nil) - if commitValue != nil { - commitStr := commitValue.(string) - commit = &commitStr - } - name := &model.SourceName{ - Name: nameStr, - Tag: tag, - Commit: commit, - } - - namespace := &model.SourceNamespace{ - Namespace: namespaceStr, - Names: []*model.SourceName{name}, - } - - src := model.Source{ - Type: srcType, - Namespaces: []*model.SourceNamespace{namespace}, - } - return &src -} diff --git a/pkg/assembler/backends/neo4j/vulnEqual.go b/pkg/assembler/backends/neo4j/vulnEqual.go deleted file mode 100644 index f55da57a9e..0000000000 --- a/pkg/assembler/backends/neo4j/vulnEqual.go +++ /dev/null @@ -1,205 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" -) - -func (c *neo4jClient) VulnEqualList(ctx context.Context, vulnEqualSpec model.VulnEqualSpec, after *string, first *int) (*model.VulnEqualConnection, error) { - return nil, fmt.Errorf("not implemented: VulnEqualList") -} - -// TODO (pxp928): fix for new vulnerability -func (c *neo4jClient) VulnEqual(ctx context.Context, vulnEqualSpec *model.VulnEqualSpec) ([]*model.VulnEqual, error) { - - // // TODO: Fix validation - // queryAll := true - // // queryAll, err := helper.ValidateCveOrGhsaQueryInput(isVulnerabilitySpec.Vulnerability) - // // if err != nil { - // // return nil, err - // // } - - // session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - // defer session.Close() - - // aggregateIsVulnerability := []*model.IsVulnerability{} - - // if queryAll || isVulnerabilitySpec.Vulnerability != nil && isVulnerabilitySpec.Vulnerability.Cve != nil { - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query CVE - // query := "MATCH (root:Osv)-[:OsvHasID]->(osvID:OsvID)" + - // "-[:subject]-(isVulnerability:IsVulnerability)-[:alias]-(cveID:CveID)<-[:CveHasID]" + - // "-(cveYear:CveYear)<-[:CveIsYear]-(rootCve:Cve)" - // sb.WriteString(query) - - // returnValue := " RETURN osvID.id, isVulnerability, cveYear.year, cveID.id" - - // setOSVMatchValues(&sb, isVulnerabilitySpec.Osv, &firstMatch, queryValues) - // if isVulnerabilitySpec.Vulnerability != nil && isVulnerabilitySpec.Vulnerability.Cve != nil { - // setCveMatchValues(&sb, isVulnerabilitySpec.Vulnerability.Cve, &firstMatch, queryValues) - // } - // setIsVulnerabilityValues(&sb, isVulnerabilitySpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedIsVulnerability := []*model.IsVulnerability{} - - // for result.Next() { - // id := result.Record().Values[0].(string) - // osv := generateModelOsv(id) - - // idStr := result.Record().Values[3].(string) - // yearStr := result.Record().Values[3].(int) - // cve := generateModelCve(yearStr, idStr) - - // isVulnerabilityNode := dbtype.Node{} - // if result.Record().Values[1] != nil { - // isVulnerabilityNode = result.Record().Values[6].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("isVulnerability Node not found in neo4j") - // } - - // isVulnerability := generateModelIsVulnerability(osv, cve, isVulnerabilityNode.Props[justification].(string), - // isVulnerabilityNode.Props[origin].(string), isVulnerabilityNode.Props[collector].(string)) - - // collectedIsVulnerability = append(collectedIsVulnerability, isVulnerability) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedIsVulnerability, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateIsVulnerability = append(aggregateIsVulnerability, result.([]*model.IsVulnerability)...) - // } - - // if queryAll || isVulnerabilitySpec.Vulnerability != nil && isVulnerabilitySpec.Vulnerability.Ghsa != nil { - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // // query GHSA - // query := "MATCH (root:Osv)-[:OsvHasID]->(osvID:OsvID)" + - // "-[:subject]-(isVulnerability:IsVulnerability)-[:alias]-(ghsaID:GhsaID)<-[:GhsaHasID]" + - // "-(rootGhsa:Ghsa)" - // sb.WriteString(query) - - // returnValue := " RETURN osvID.id, isVulnerability, ghsaID.id" - - // setOSVMatchValues(&sb, isVulnerabilitySpec.Osv, &firstMatch, queryValues) - // if isVulnerabilitySpec.Vulnerability != nil && isVulnerabilitySpec.Vulnerability.Ghsa != nil { - // setGhsaMatchValues(&sb, isVulnerabilitySpec.Vulnerability.Ghsa, &firstMatch, queryValues) - // } - // setIsVulnerabilityValues(&sb, isVulnerabilitySpec, &firstMatch, queryValues) - // sb.WriteString(returnValue) - - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // collectedIsVulnerability := []*model.IsVulnerability{} - - // for result.Next() { - // id := result.Record().Values[0].(string) - // osv := generateModelOsv(id) - - // idStr := result.Record().Values[2].(string) - // ghsa := generateModelGhsa(idStr) - - // isVulnerabilityNode := dbtype.Node{} - // if result.Record().Values[6] != nil { - // isVulnerabilityNode = result.Record().Values[1].(dbtype.Node) - // } else { - // return nil, gqlerror.Errorf("isVulnerability Node not found in neo4j") - // } - - // isVulnerability := generateModelIsVulnerability(osv, ghsa, isVulnerabilityNode.Props[justification].(string), - // isVulnerabilityNode.Props[origin].(string), isVulnerabilityNode.Props[collector].(string)) - - // collectedIsVulnerability = append(collectedIsVulnerability, isVulnerability) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // return collectedIsVulnerability, nil - // }) - // if err != nil { - // return nil, err - // } - // aggregateIsVulnerability = append(aggregateIsVulnerability, result.([]*model.IsVulnerability)...) - // } - // return aggregateIsVulnerability, nil - return []*model.VulnEqual{}, fmt.Errorf("not implemented - VulnEqual") -} - -// func setIsVulnerabilityValues(sb *strings.Builder, isVulnerabilitySpec *model.IsVulnerabilitySpec, firstMatch *bool, queryValues map[string]any) { -// if isVulnerabilitySpec.Justification != nil { -// matchProperties(sb, *firstMatch, "isVulnerability", justification, "$"+justification) -// *firstMatch = false -// queryValues["justification"] = isVulnerabilitySpec.Justification -// } -// if isVulnerabilitySpec.Origin != nil { -// matchProperties(sb, *firstMatch, "isVulnerability", origin, "$"+origin) -// *firstMatch = false -// queryValues[origin] = isVulnerabilitySpec.Origin -// } -// if isVulnerabilitySpec.Collector != nil { -// matchProperties(sb, *firstMatch, "isVulnerability", collector, "$"+collector) -// *firstMatch = false -// queryValues[collector] = isVulnerabilitySpec.Collector -// } -// } - -// func generateModelIsVulnerability(osv *model.Osv, vuln model.CveOrGhsa, justification, origin, collector string) *model.IsVulnerability { -// isVulnerability := model.IsVulnerability{ -// Osv: osv, -// Vulnerability: vuln, -// Justification: justification, -// Origin: origin, -// Collector: collector, -// } -// return &isVulnerability -// } - -func (c *neo4jClient) IngestVulnEqual(ctx context.Context, vulnerability model.IDorVulnerabilityInput, otherVulnerability model.IDorVulnerabilityInput, vulnEqual model.VulnEqualInputSpec) (string, error) { - return "", fmt.Errorf("not implemented - IngestVulnEqual") -} - -func (c *neo4jClient) IngestVulnEquals(ctx context.Context, vulnerabilities []*model.IDorVulnerabilityInput, otherVulnerabilities []*model.IDorVulnerabilityInput, vulnEquals []*model.VulnEqualInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented - IngestVulnEquals") -} diff --git a/pkg/assembler/backends/neo4j/vulnMetadata.go b/pkg/assembler/backends/neo4j/vulnMetadata.go deleted file mode 100644 index 2f6d270dec..0000000000 --- a/pkg/assembler/backends/neo4j/vulnMetadata.go +++ /dev/null @@ -1,39 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" -) - -func (c *neo4jClient) VulnerabilityMetadataList(ctx context.Context, vulnerabilityMetadataSpec model.VulnerabilityMetadataSpec, after *string, first *int) (*model.VulnerabilityMetadataConnection, error) { - return nil, fmt.Errorf("not implemented: VulnerabilityMetadataList") -} - -func (c *neo4jClient) IngestVulnerabilityMetadata(ctx context.Context, vulnerability model.IDorVulnerabilityInput, vulnerabilityMetadata model.VulnerabilityMetadataInputSpec) (string, error) { - return "", fmt.Errorf("not implemented - IngestVulnerabilityMetadata") -} - -func (c *neo4jClient) IngestBulkVulnerabilityMetadata(ctx context.Context, vulnerabilities []*model.IDorVulnerabilityInput, vulnerabilityMetadataList []*model.VulnerabilityMetadataInputSpec) ([]string, error) { - return []string{}, fmt.Errorf("not implemented - IngestBulkVulnerabilityMetadata") -} - -func (c *neo4jClient) VulnerabilityMetadata(ctx context.Context, vulnerabilityMetadataSpec *model.VulnerabilityMetadataSpec) ([]*model.VulnerabilityMetadata, error) { - return []*model.VulnerabilityMetadata{}, fmt.Errorf("not implemented - VulnerabilityMetadata") -} diff --git a/pkg/assembler/backends/neo4j/vulnerability.go b/pkg/assembler/backends/neo4j/vulnerability.go deleted file mode 100644 index 160ba6e4b9..0000000000 --- a/pkg/assembler/backends/neo4j/vulnerability.go +++ /dev/null @@ -1,210 +0,0 @@ -// -// 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 neo4j - -import ( - "context" - "fmt" - - "github.com/guacsec/guac/pkg/assembler/graphql/model" -) - -func (c *neo4jClient) VulnerabilityList(ctx context.Context, vulnSpec model.VulnerabilitySpec, after *string, first *int) (*model.VulnerabilityConnection, error) { - return nil, fmt.Errorf("not implemented: VulnerabilityList") -} - -// TODO (pxp928): fix for new vulnerability -func (c *neo4jClient) Vulnerabilities(ctx context.Context, vulnSpec *model.VulnerabilitySpec) ([]*model.Vulnerability, error) { - // fields: [year cveId cveId.id] - //fields := getPreloads(ctx) - //cveIDImplRequired := false - // for _, f := range fields { - // if f == cvdID { - // cveIDImplRequired = true - // break - // } - // } - - // if !cveIDImplRequired { - // return c.cveYear(ctx, cveSpec) - // } - - // session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - // defer session.Close() - - // var sb strings.Builder - // var firstMatch bool = true - // queryValues := map[string]any{} - - // sb.WriteString("MATCH (type:vulnType)->[:VulneHasID]->(vulnID:VulnID)") - - // setCveMatchValues(&sb, vulnSpec, &firstMatch, queryValues) - - // sb.WriteString(" RETURN type.year, vulnID.id") - - // TODO (pxp928): fix for new vulnerability - // result, err := session.ReadTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - - // result, err := tx.Run(sb.String(), queryValues) - // if err != nil { - // return nil, err - // } - - // cvesPerYear := map[int][]*model.CVEId{} - // for result.Next() { - // cveID := &model.CVEId{ - // CveID: result.Record().Values[1].(string), - // } - // cvesPerYear[result.Record().Values[0].(int)] = append(cvesPerYear[result.Record().Values[0].(int)], cveID) - // } - // if err = result.Err(); err != nil { - // return nil, err - // } - - // cves := []*model.Cve{} - // for year := range cvesPerYear { - //cve := &model.Cve{ - // Year: year, - // CveIds: cvesPerYear[year], - //} - // cves = append(cves, cve) - // } - - //return cve, nil - // }) - // if err != nil { - // return nil, err - // } - //return result.(*model.Cve), nil - return []*model.Vulnerability{}, fmt.Errorf("not implemented - Vulnerabilities") -} - -// func (c *neo4jClient) cveYear(ctx context.Context, cveSpec *model.VulnerabilitySpec) ([]*model.Vulnerability, error) { -// session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) -// defer session.Close() - -// var sb strings.Builder -// queryValues := map[string]any{} - -// sb.WriteString("MATCH (n:Cve)-[:CveIsYear]->(cveYear:CveYear)") - -// if cveSpec.Year != nil { -// matchProperties(&sb, true, "cveYear", "year", "$cveYear") -// queryValues["cveYear"] = cveSpec.Year -// } - -// sb.WriteString(" RETURN cveYear.year") - -// result, err := session.ReadTransaction( -// func(tx neo4j.Transaction) (interface{}, error) { -// // FIXME update to GHSA without root node. -// // result, err := tx.Run(sb.String(), queryValues) -// // if err != nil { -// // return nil, err -// // } - -// // cves := []*model.Cve{} -// // for result.Next() { -// cve := &model.Cve{ -// // Year: result.Record().Values[0].(int), -// // CveIds: []*model.CVEId{}, -// } -// // cves = append(cves, cve) -// // } -// // if err = result.Err(); err != nil { -// // return nil, err -// // } - -// return cve, nil -// }) -// if err != nil { -// return nil, err -// } - -// return result.([]*model.Cve), nil -// } - -// func setCveMatchValues(sb *strings.Builder, cve *model.CVESpec, firstMatch *bool, queryValues map[string]any) { -// if cve != nil { -// if cve.Year != nil { -// matchProperties(sb, *firstMatch, "cveYear", "year", "$cveYear") -// queryValues["cveYear"] = cve.Year -// *firstMatch = false -// } - -// if cve.CveID != nil { -// matchProperties(sb, *firstMatch, "cveID", "id", "$cveID") -// queryValues["cveID"] = strings.ToLower(*cve.CveID) -// *firstMatch = false -// } -// } -// } - -func (c *neo4jClient) IngestVulnerabilities(ctx context.Context, vulns []*model.IDorVulnerabilityInput) ([]*model.VulnerabilityIDs, error) { - return []*model.VulnerabilityIDs{}, fmt.Errorf("not implemented: IngestVulnerabilities") -} - -// TODO (pxp928): fix for new vulnerability -func (c *neo4jClient) IngestVulnerability(ctx context.Context, vuln model.IDorVulnerabilityInput) (*model.VulnerabilityIDs, error) { - // session := c.driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) - // defer session.Close() - - // values := map[string]any{} - // values["year"] = cve.Year - // values["id"] = strings.ToLower(cve.CveID) - - // result, err := session.WriteTransaction( - // func(tx neo4j.Transaction) (interface{}, error) { - // query := `MERGE (root:Cve) - // MERGE (root) -[:CveIsYear]-> (cveYear:CveYear{year:$year}) - // MERGE (cveYear) -[:CveHasID]-> (cveID:CveID{id:$id}) - // RETURN cveYear.year, cveID.id` - // result, err := tx.Run(query, values) - // if err != nil { - // return nil, err - // } - - // // query returns a single record - // record, err := result.Single() - // if err != nil { - // return nil, err - // } - - // cveIdStr := record.Values[1].(string) - // yearStr := record.Values[0].(int) - // cve := generateModelCve(yearStr, cveIdStr) - - // return cve, nil - // }) - // if err != nil { - // return nil, err - // } - - // return result.(*model.Cve), nil - return nil, fmt.Errorf("not implemented: IngestVulnerabilities") -} - -// // TODO: update to pass in the ID from neo4j -// func generateModelCve(yearStr int, idStr string) *model.Cve { -// // FIXME update to GHSA without root node. -// // id := &model.CVEId{CveID: idStr} -// cve := model.Cve{ -// Year: yearStr, -// // CveIds: []*model.CVEId{id}, -// } -// return &cve -// } diff --git a/pkg/assembler/backends/neptune/neptune.go b/pkg/assembler/backends/neptune/neptune.go deleted file mode 100644 index d5adc3ee41..0000000000 --- a/pkg/assembler/backends/neptune/neptune.go +++ /dev/null @@ -1,185 +0,0 @@ -// -// 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 neptune - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "net/http" - "os" - "time" - - jsoniter "github.com/json-iterator/go" - - "github.com/aws/aws-sdk-go-v2/aws" - v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" - "github.com/aws/aws-sdk-go-v2/config" - "github.com/guacsec/guac/pkg/assembler/backends" - "github.com/guacsec/guac/pkg/assembler/backends/neo4j" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var json = jsoniter.ConfigCompatibleWithStandardLibrary - -const neptuneServiceName = "neptune-db" - -type NeptuneConfig struct { - Endpoint string - Port int - Region string - User string - Realm string -} - -// flags holds the command-line flags for Neptune configuration -var flags = struct { - endpoint string - port int - region string - user string - realm string -}{} - -func init() { - backends.Register("neptune", getBackend, registerFlags, parseFlags) -} - -// registerFlags registers Neptune-specific command line flags -func registerFlags(cmd *cobra.Command) error { - flagSet := cmd.Flags() - flagSet.StringVar(&flags.endpoint, "neptune-endpoint", "localhost", "address to neptune db") - flagSet.IntVar(&flags.port, "neptune-port", 8182, "port used for neptune db connection") - flagSet.StringVar(&flags.region, "neptune-region", "us-east-1", "region to connect to neptune db") - flagSet.StringVar(&flags.user, "neptune-user", "", "neptune user credential to connect to graph db") - flagSet.StringVar(&flags.realm, "neptune-realm", "neptune", "realm to connect to graph db") - - if err := viper.BindPFlags(flagSet); err != nil { - return fmt.Errorf("failed to bind flags: %w", err) - } - - // set values from guac.yaml if present - flags.endpoint = viper.GetString("neptune-endpoint") - flags.port = viper.GetInt("neptune-port") - flags.region = viper.GetString("neptune-region") - flags.user = viper.GetString("neptune-user") - flags.realm = viper.GetString("neptune-realm") - - return nil -} - -// parseFlags returns the Neptune configuration from parsed flags -func parseFlags(ctx context.Context) (backends.BackendArgs, error) { - return &NeptuneConfig{ - Endpoint: flags.endpoint, - Port: flags.port, - Region: flags.region, - User: flags.user, - Realm: flags.realm, - }, nil -} - -func getBackend(ctx context.Context, args backends.BackendArgs) (backends.Backend, error) { - config, ok := args.(*NeptuneConfig) - if !ok { - return nil, fmt.Errorf("failed to assert neptune config from backend args") - } - neptuneRequestURL := fmt.Sprintf("https://%s:%d/opencypher", - config.Endpoint, config.Port) - neptuneToken, err := generateNeptuneToken(ctx, neptuneRequestURL, - config.Region) - if err != nil { - return nil, fmt.Errorf("failed to create password for neptune: %w", err) - } - - neptuneDBAddr := fmt.Sprintf("bolt+s://%s:%d/opencypher", - config.Endpoint, config.Port) - nargs := &neo4j.Neo4jConfig{ - User: config.User, - Pass: neptuneToken, - DBAddr: neptuneDBAddr, - Realm: config.Realm, - } - return backends.Get("neo4j", ctx, nargs) -} - -// generateNeptuneToken generates a token for neptune using the AWS SDK. -func generateNeptuneToken(ctx context.Context, neptuneURL string, region string) (string, error) { - req, err := http.NewRequest(http.MethodGet, neptuneURL, nil) - if err != nil { - return "", fmt.Errorf("error creating http request for neptune: %w", err) - } - - signer, creds, err := getAWSRequestSigner(ctx) - if err != nil { - return "", fmt.Errorf("error creating AWS request signer: %w", err) - } - - // SHA-256 hash of empty body (required by v4.SignHTTP) - emptyHash := sha256.Sum256([]byte{}) - payloadHash := hex.EncodeToString(emptyHash[:]) - - if err := signer.SignHTTP(ctx, creds, req, payloadHash, neptuneServiceName, region, time.Now()); err != nil { - return "", fmt.Errorf("error signing neptune request: %w", err) - } - - headers := []string{"Authorization", "X-Amz-Date", "X-Amz-Security-Token"} - hdrMap := make(map[string]string) - for _, h := range headers { - hdrMap[h] = req.Header.Get(h) - } - - hdrMap["Host"] = req.Host - hdrMap["HttpMethod"] = req.Method - password, err := json.Marshal(hdrMap) - if err != nil { - return "", fmt.Errorf("error marshalling header map: %w", err) - } - - return string(password), nil -} - -// This method returns the AWS signer to be used for signing the request to be -// sent to Neptune Cluster. It checks for the presence of AWS_ACCESS_KEY_ID, -// AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN in the environment. If not -// found, it loads the default AWS config and gets the credentials from the config. -func getAWSRequestSigner(ctx context.Context) (*v4.Signer, aws.Credentials, error) { - accessKeyID := os.Getenv("AWS_ACCESS_KEY_ID") - secretAccessKey := os.Getenv("AWS_SECRET_ACCESS_KEY") - sessionToken := os.Getenv("AWS_SESSION_TOKEN") - - if accessKeyID != "" && secretAccessKey != "" && sessionToken != "" { - return v4.NewSigner(), aws.Credentials{ - AccessKeyID: accessKeyID, - SecretAccessKey: secretAccessKey, - SessionToken: sessionToken, - }, nil - } - - cfg, err := config.LoadDefaultConfig(ctx) - if err != nil { - return nil, aws.Credentials{}, err - } - - creds, err := cfg.Credentials.Retrieve(ctx) - if err != nil { - return nil, aws.Credentials{}, err - } - - return v4.NewSigner(), creds, nil -} diff --git a/pkg/cli/store.go b/pkg/cli/store.go index 22ddb60569..3e036b3fbd 100644 --- a/pkg/cli/store.go +++ b/pkg/cli/store.go @@ -47,7 +47,7 @@ func init() { set.String("csub-tls-cert-file", "", "path to the TLS certificate in PEM format for collect-sub service") set.String("csub-tls-key-file", "", "path to the TLS key in PEM format for collect-sub service") - set.String("gql-backend", "keyvalue", "backend used for graphql api server: [keyvalue | arango (experimental) | ent (experimental) | neo4j (unmaintained)]") + set.String("gql-backend", "keyvalue", "backend used for graphql api server: [keyvalue | arango (experimental) | ent (experimental)]") set.Int("gql-listen-port", 8080, "port used for graphql api server") set.String("gql-tls-cert-file", "", "path to the TLS certificate in PEM format for graphql api server") set.String("gql-tls-key-file", "", "path to the TLS key in PEM format for graphql api server")