From 5e2e06221d33392619ed2a76addf344011c34c36 Mon Sep 17 00:00:00 2001 From: rickbijkerk Date: Fri, 5 Jan 2024 16:55:44 +0100 Subject: [PATCH] Persisted operations + GCS integration improvements (#13) A MR with small tweaks i had to do to make persisted operations work together with a GCS bucket changes include: - No longer forwarding 'operationName' - Minor tweaks in documentation regarding fetching from GCS bucket - Properly reading the gcs downloaded files from disk by including the directory --------- Co-authored-by: Rick Bijkerk --- cmd/main.go | 1 - docs/configuration.md | 22 +++++++++---------- internal/business/gql/gql.go | 7 +++--- .../persisted_operations/dir_loader.go | 8 +++++-- .../gcp_storage_loader.go | 13 ++++++----- .../persisted_operations.go | 2 +- .../persisted_operations_test.go | 5 +++-- 7 files changed, 31 insertions(+), 27 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index a105946..f34f56f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -200,7 +200,6 @@ func ValidationRules(schema *schema.Provider, tks *tokens.MaxTokensRule) func(ne } operationSource := &ast.Source{ - Name: payload.OperationName, Input: payload.Query, } err = tks.Validate(operationSource) diff --git a/docs/configuration.md b/docs/configuration.md index 61e8b04..b17af87 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -23,7 +23,7 @@ target: host: http://localhost:8081 timeout: 10s keep_alive: 180s - + schema: # Path to a local file in which the schema can be found path: "./schema.graphql" @@ -32,19 +32,19 @@ schema: # after each `schema.auto_reload.interval` has passed. auto_reload: # Enable automatic file reloading - enabled: "true" + enabled: true # The interval in which the schema file should be reloaded interval: 5m persisted_operations: # Enable or disable the feature, enabled by default - enabled: "true" + enabled: true # Fail unknown operations, disable this feature to allow unknown operations to reach your GraphQL API - fail_unknown_operations: "true" + fail_unknown_operations: true # Store is the location on local disk where go-graphql-armor can find the persisted operations, it loads any `*.json` files on disk store: "./store" reload: - enabled: "true" + enabled: true # The interval in which the local store dir is read and refreshes the internal state interval: 5m # The timeout for the remote operation @@ -52,27 +52,27 @@ persisted_operations: remote: # Load persisted operations from a GCP Cloud Storage bucket. # Will look at all the objects in the bucket and try to load any object with a `.json` extension - gcp_bucket: "gs://somebucket" + gcp_bucket: "somebucket" max_aliases: # Enable the feature - enable: "true" + enable: true # The maximum number of allowed aliases within a single request. max: 15 # Reject the request when the rule fails. Disable this to allow the request - reject_on_failure: "true" + reject_on_failure: true block_field_suggestions: - enabled: "true" + enabled: true mask: [redacted] max_tokens: # Enable the feature - enable: "true" + enable: true # The maximum number of allowed tokens within a single request. max: 10000 # Reject the request when the rule fails. Disable this to allow the request regardless of token count. - reject_on_failure: "true" + reject_on_failure: true ``` For a more in-depth view of each option visit the accompanying documentation page. diff --git a/internal/business/gql/gql.go b/internal/business/gql/gql.go index a74db16..8fc385a 100644 --- a/internal/business/gql/gql.go +++ b/internal/business/gql/gql.go @@ -8,10 +8,9 @@ import ( ) type RequestPayload struct { - OperationName string `json:"operationName"` - Variables map[string]interface{} `json:"variables"` - Query string `json:"query"` - Extensions Extensions `json:"extensions"` + Variables map[string]interface{} `json:"variables"` + Query string `json:"query"` + Extensions Extensions `json:"extensions"` } type Extensions struct { diff --git a/internal/business/persisted_operations/dir_loader.go b/internal/business/persisted_operations/dir_loader.go index 5fc6642..5f76960 100644 --- a/internal/business/persisted_operations/dir_loader.go +++ b/internal/business/persisted_operations/dir_loader.go @@ -3,6 +3,7 @@ package persisted_operations import ( "context" "encoding/json" + "fmt" "os" "path/filepath" ) @@ -39,13 +40,16 @@ func (d *DirLoader) Load(ctx context.Context) (map[string]string, error) { continue } if filepath.Ext(file.Name()) == ".json" { - contents, err := os.ReadFile(file.Name()) + filePath := filepath.Join(d.path, file.Name()) + contents, err := os.ReadFile(filePath) if err != nil { continue } - // append to map + err = json.Unmarshal(contents, &result) + if err != nil { + fmt.Println(err) continue } } diff --git a/internal/business/persisted_operations/gcp_storage_loader.go b/internal/business/persisted_operations/gcp_storage_loader.go index 5179652..94fbe0b 100644 --- a/internal/business/persisted_operations/gcp_storage_loader.go +++ b/internal/business/persisted_operations/gcp_storage_loader.go @@ -45,38 +45,39 @@ func (g *GcpStorageLoader) Load(ctx context.Context) error { break } if err != nil { + errs = append(errs, err) break } ctx, cancel := context.WithTimeout(ctx, time.Second*50) - f, err := os.Create(filepath.Join(g.store, attrs.Name)) + file, err := os.Create(filepath.Join(g.store, attrs.Name)) if err != nil { cancel() errs = append(errs, fmt.Errorf("os.Create: %w", err)) continue } - rc, err := g.client.Bucket(g.bucket).Object(attrs.Name).NewReader(ctx) + reader, err := g.client.Bucket(g.bucket).Object(attrs.Name).NewReader(ctx) if err != nil { cancel() errs = append(errs, fmt.Errorf("Object(%q).NewReader: %w", attrs.Name, err)) continue } - if _, err := io.Copy(f, rc); err != nil { + if _, err := io.Copy(file, reader); err != nil { cancel() errs = append(errs, fmt.Errorf("io.Copy: %w", err)) continue } - if err = f.Close(); err != nil { + if err = file.Close(); err != nil { cancel() - errs = append(errs, fmt.Errorf("f.Close: %w", err)) + errs = append(errs, fmt.Errorf("file.Close: %w", err)) } cancel() - _ = rc.Close() + _ = reader.Close() } return errors.Join(errs...) diff --git a/internal/business/persisted_operations/persisted_operations.go b/internal/business/persisted_operations/persisted_operations.go index dbb4fa4..081ec52 100644 --- a/internal/business/persisted_operations/persisted_operations.go +++ b/internal/business/persisted_operations/persisted_operations.go @@ -51,7 +51,7 @@ type Config struct { } // Remote strategies for fetching persisted operations Remote struct { - GcpBucket string `conf:"gs://something/foo" yaml:"gcp_bucket"` + GcpBucket string `conf:"your_bucket_name" yaml:"gcp_bucket"` } FailUnknownOperations bool `conf:"default:false" yaml:"fail_unknown_operations"` } diff --git a/internal/business/persisted_operations/persisted_operations_test.go b/internal/business/persisted_operations/persisted_operations_test.go index 2eda9dc..53d634f 100644 --- a/internal/business/persisted_operations/persisted_operations_test.go +++ b/internal/business/persisted_operations/persisted_operations_test.go @@ -127,10 +127,11 @@ func TestNewPersistedOperations(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "query { foobar }", payload.Query) - assert.Equal(t, int64(101), r.ContentLength) + assert.Equal(t, int64(82), r.ContentLength) length, _ := json.Marshal(payload) - assert.Equal(t, 101, len(length)) + + assert.Equal(t, 82, len(length)) } return http.HandlerFunc(fn) },