diff --git a/Gemfile b/Gemfile index c47921bd6..c50835e90 100644 --- a/Gemfile +++ b/Gemfile @@ -11,7 +11,7 @@ gem 'puma', '~> 3.12' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder # gem 'jbuilder', '~> 2.5' # Use Redis adapter to run Action Cable in production -gem 'hiredis' +gem 'redis', '~> 4.0' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' @@ -68,14 +68,13 @@ gem 'prometheus_exporter' gem 'activerecord-import' gem 'oj' +gem 'newrelic_rpm' gem 'gitlab-sidekiq-fetcher', require: 'sidekiq-reliable-fetch' gem 'uuid' gem 'openscap_parser', '~> 1.0.0' -gem 'graphql-cache' - group :development, :test do gem 'brakeman' gem 'byebug', platforms: %i[mri mingw x64_mingw] diff --git a/Gemfile.lock b/Gemfile.lock index db95142bb..b34c20c71 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -145,10 +145,7 @@ GEM graphql-batch (0.4.2) graphql (>= 1.3, < 2) promise.rb (~> 0.7.2) - graphql-cache (0.6.0) - graphql (~> 1, > 1.8) hashdiff (1.0.0) - hiredis (0.6.3) i18n (1.8.2) concurrent-ruby (~> 1.0) io-console (0.5.4) @@ -186,6 +183,7 @@ GEM msgpack (1.3.1) multi_json (1.14.1) multipart-post (2.1.1) + newrelic_rpm (6.8.0.360) nio4r (2.5.2) nokogiri (1.10.9) mini_portile2 (~> 2.4.0) @@ -372,12 +370,11 @@ DEPENDENCIES graphiql-rails graphql graphql-batch - graphql-cache - hiredis irb (>= 1.2) listen (>= 3.0.5, < 3.2) minitest-reporters mocha + newrelic_rpm oj openscap_parser (~> 1.0.0) pg @@ -390,6 +387,7 @@ DEPENDENCIES racecar rack-cors rails (~> 5.2.1) + redis (~> 4.0) rspec-rails rswag-api rswag-specs diff --git a/app/graphql/schema.rb b/app/graphql/schema.rb index 46e9eb7d9..1558ef3f7 100644 --- a/app/graphql/schema.rb +++ b/app/graphql/schema.rb @@ -15,5 +15,6 @@ class Schema < GraphQL::Schema mutation Types::Mutation lazy_resolve(Promise, :sync) use GraphQL::Batch - use GraphQL::Cache + use GraphQL::Execution::Interpreter + use GraphQL::Analysis::AST end diff --git a/app/graphql/types/base_object.rb b/app/graphql/types/base_object.rb index 651e79b25..4f3c7cf62 100644 --- a/app/graphql/types/base_object.rb +++ b/app/graphql/types/base_object.rb @@ -9,7 +9,6 @@ class BaseObject < GraphQL::Types::Relay::BaseObject global_id_field :global_id field :node, field: GraphQL::Relay::Node.field field :nodes, field: GraphQL::Relay::Node.plural_field - field_class ::GraphQL::Cache::Field class << self def model_class(new_model_class = nil) diff --git a/app/graphql/types/benchmark.rb b/app/graphql/types/benchmark.rb index 478123d38..da3fb5119 100644 --- a/app/graphql/types/benchmark.rb +++ b/app/graphql/types/benchmark.rb @@ -6,13 +6,13 @@ class Benchmark < Types::BaseObject graphql_name 'Benchmark' description 'A representation of a SCAP Security Guide version' - field :id, ID, null: false, cache: true - field :description, String, null: true, cache: true - field :title, String, null: false, cache: true - field :ref_id, String, null: false, cache: true - field :version, String, null: false, cache: true - field :profiles, [::Types::Profile], null: true, cache: true - field :rules, [::Types::Rule], null: true, cache: true + field :id, ID, null: false + field :description, String, null: true + field :title, String, null: false + field :ref_id, String, null: false + field :version, String, null: false + field :profiles, [::Types::Profile], null: true + field :rules, [::Types::Rule], null: true def profiles object.profiles.canonical diff --git a/app/graphql/types/business_objective.rb b/app/graphql/types/business_objective.rb index 9a9f69252..1d7c641c0 100644 --- a/app/graphql/types/business_objective.rb +++ b/app/graphql/types/business_objective.rb @@ -6,7 +6,7 @@ class BusinessObjective < Types::BaseObject graphql_name 'BusinessObjective' description 'A Business Objective registered in Insights Compliance' - field :id, ID, null: false, cache: true - field :title, String, null: false, cache: true + field :id, ID, null: false + field :title, String, null: false end end diff --git a/app/graphql/types/interfaces/rules_preload.rb b/app/graphql/types/interfaces/rules_preload.rb index b4f5a8c67..9e2f9f0d1 100644 --- a/app/graphql/types/interfaces/rules_preload.rb +++ b/app/graphql/types/interfaces/rules_preload.rb @@ -4,7 +4,6 @@ # rule results, compliant,and references module RulesPreload include GraphQL::Schema::Interface - field_class GraphQL::Cache::Field def rules(args = {}) context[:parent_profile_id] ||= {} diff --git a/app/graphql/types/profile.rb b/app/graphql/types/profile.rb index 987f86562..257585d93 100644 --- a/app/graphql/types/profile.rb +++ b/app/graphql/types/profile.rb @@ -13,16 +13,15 @@ class Profile < Types::BaseObject graphql_name 'Profile' description 'A Profile registered in Insights Compliance' - field :id, ID, null: false, cache: true - field :name, String, null: false, cache: true - field :description, String, null: true, cache: true - field :ref_id, String, null: false, cache: true - field :compliance_threshold, Float, null: false, cache: true - field :benchmark_id, ID, null: false, cache: true - field :account_id, ID, null: false, cache: true - field :policy, Types::Profile, null: true, cache: true - field :rules, [::Types::Rule], null: true, cache: true, - extras: [:lookahead] do + field :id, ID, null: false + field :name, String, null: false + field :description, String, null: true + field :ref_id, String, null: false + field :compliance_threshold, Float, null: false + field :benchmark_id, ID, null: false + field :account_id, ID, null: false + field :policy, Types::Profile, null: true + field :rules, [::Types::Rule], null: true, extras: [:lookahead] do argument :system_id, String, 'System ID to filter by', required: false argument :identifier, String, @@ -30,44 +29,43 @@ class Profile < Types::BaseObject argument :references, [String], 'Rule references to filter by', required: false end - field :hosts, [::Types::System], null: true, cache: true - field :benchmark, ::Types::Benchmark, null: true, cache: true - field :business_objective, ::Types::BusinessObjective, null: true, - cache: true - field :business_objective_id, ID, null: true, cache: true - field :total_host_count, Int, null: false, cache: true - field :external, Boolean, null: false, cache: true - - field :score, Float, null: false, cache: true do + field :hosts, [::Types::System], null: true + field :benchmark, ::Types::Benchmark, null: true + field :business_objective, ::Types::BusinessObjective, null: true + field :business_objective_id, ID, null: true + field :total_host_count, Int, null: false + field :external, Boolean, null: false + + field :score, Float, null: false do argument :system_id, String, 'Latest TestResult score for this system and profile', required: false end - field :compliant, Boolean, null: false, cache: true do + field :compliant, Boolean, null: false do argument :system_id, String, 'Is a system compliant with this profile?', required: false end - field :rules_passed, Int, null: false, cache: true do + field :rules_passed, Int, null: false do argument :system_id, String, 'Rules passed for a system and a profile', required: false end - field :rules_failed, Int, null: false, cache: true do + field :rules_failed, Int, null: false do argument :system_id, String, 'Rules failed for a system and a profile', required: false end - field :last_scanned, String, null: false, cache: true do + field :last_scanned, String, null: false do argument :system_id, String, 'Last time this profile was scanned for a system', required: false end - field :compliant_host_count, Int, null: false, cache: true + field :compliant_host_count, Int, null: false - field :major_os_version, String, null: false, cache: true + field :major_os_version, String, null: false def compliant_host_count ::CollectionLoader.for(object.class, :hosts).load(object).then do |hosts| diff --git a/app/graphql/types/rule.rb b/app/graphql/types/rule.rb index 2c7b69477..588708ea3 100644 --- a/app/graphql/types/rule.rb +++ b/app/graphql/types/rule.rb @@ -6,17 +6,17 @@ class Rule < Types::BaseObject graphql_name 'Rule' description 'A Rule registered in Insights Compliance' - field :id, ID, null: false, cache: true - field :title, String, null: false, cache: true - field :ref_id, String, null: false, cache: true - field :rationale, String, null: true, cache: true - field :description, String, null: true, cache: true - field :severity, String, null: false, cache: true - field :remediation_available, Boolean, null: false, cache: true - field :profiles, [::Types::Profile], null: true, cache: true - field :identifier, String, null: true, cache: true - field :references, String, null: true, cache: true - field :compliant, Boolean, null: false, cache: true do + field :id, ID, null: false + field :title, String, null: false + field :ref_id, String, null: false + field :rationale, String, null: true + field :description, String, null: true + field :severity, String, null: false + field :remediation_available, Boolean, null: false + field :profiles, [::Types::Profile], null: true + field :identifier, String, null: true + field :references, String, null: true + field :compliant, Boolean, null: false do argument :system_id, String, 'Is a system compliant?', required: false argument :profile_id, String, 'Is a system compliant with this profile?', @@ -35,7 +35,7 @@ def references if context[:"rule_references_#{object.id}"].nil? ::CollectionLoader.for(::Rule, :rule_references) .load(object).then do |references| - references.map { |ref| { href: ref.href, label: ref.label } }.to_json + generate_references_json(references) end else references_from_context @@ -46,9 +46,7 @@ def references_from_context ::RecordLoader.for(::RuleReference) .load_many(context[:"rule_references_#{object.id}"]) .then do |references| - references.compact.map do |ref| - { href: ref.href, label: ref.label } - end.to_json + generate_references_json(references) end end @@ -75,6 +73,12 @@ def profile_id(args) args[:profile_id] || context[:parent_profile_id][object.id] end + def generate_references_json(references) + references.compact.map do |ref| + { href: ref.href, label: ref.label } + end.to_json + end + def latest_test_result_batch(args) ::RecordLoader.for( ::TestResult, diff --git a/app/graphql/types/system.rb b/app/graphql/types/system.rb index 5928d4f4b..b4a4dcf0b 100644 --- a/app/graphql/types/system.rb +++ b/app/graphql/types/system.rb @@ -7,26 +7,26 @@ class System < Types::BaseObject graphql_name 'System' description 'A System registered in Insights Compliance' - field :id, ID, null: false, cache: true - field :name, String, null: false, cache: true - field :profiles, [::Types::Profile], null: true, cache: true - field :compliant, Boolean, null: false, cache: true do + field :id, ID, null: false + field :name, String, null: false + field :profiles, [::Types::Profile], null: true + field :compliant, Boolean, null: false do argument :profile_id, String, 'Filter results by profile ID', required: false end - field :profile_names, String, null: false, cache: true - field :rules_passed, Int, null: false, cache: true do + field :profile_names, String, null: false + field :rules_passed, Int, null: false do argument :profile_id, String, 'Filter results by profile ID', required: false end - field :rules_failed, Int, null: false, cache: true do + field :rules_failed, Int, null: false do argument :profile_id, String, 'Filter results by profile ID', required: false end - field :rule_objects_failed, [::Types::Rule], null: true, cache: true do + field :rule_objects_failed, [::Types::Rule], null: true do description 'Rules failed by a system' end - field :last_scanned, String, null: true, cache: true do + field :last_scanned, String, null: true do argument :profile_id, String, 'Filter results by profile ID', required: false end diff --git a/app/graphql/types/test_result.rb b/app/graphql/types/test_result.rb index d43dc857d..bcc96569b 100644 --- a/app/graphql/types/test_result.rb +++ b/app/graphql/types/test_result.rb @@ -7,11 +7,11 @@ class TestResult < Types::BaseObject graphql_name 'TestResult' description 'A TestResult as recorded in Insights Compliance' - field :id, ID, null: false, cache: true - field :start_time, String, null: true, cache: true - field :end_time, String, null: false, cache: true - field :score, Float, null: false, cache: true - field :profile, ::Types::Profile, null: false, cache: true - field :host, ::Types::System, null: false, cache: true + field :id, ID, null: false + field :start_time, String, null: true + field :end_time, String, null: false + field :score, Float, null: false + field :profile, ::Types::Profile, null: false + field :host, ::Types::System, null: false end end diff --git a/config/initializers/graphql_cache.rb b/config/initializers/graphql_cache.rb deleted file mode 100644 index 709e353b2..000000000 --- a/config/initializers/graphql_cache.rb +++ /dev/null @@ -1,36 +0,0 @@ -GraphQL::Cache.configure do |config| - config.namespace = 'compliance' # Cache key prefix for keys generated by graphql-cache - config.cache = Rails.cache # The cache object to use for caching - config.logger = Rails.logger # Logger to receive cache-related log messages - config.expiry = 15552000 # 6 months (in seconds) -end - -module GraphQL - module Cache - module DeconstructorExtensions - def perform - return raw.value if method == 'lazy' - if raw.is_a?(Promise) - raw.wait - raw.value - end - super - end - end - - class Deconstructor - prepend DeconstructorExtensions - end - - class Key - def to_s - @to_s ||= [ - GraphQL::Cache.namespace, - object_clause, - arguments_clause, - field_clause, - ].flatten.compact.join(':') - end - end - end -end