Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ensure that solr checksum verification does not obscure 404 responses… #2668

Merged
merged 1 commit into from
May 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/app/main.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def self.plugins_loaded_hook(&block)
Solr.verify_checksums!
Log.info('Solr config checksum verification ok.')
else
Log.warn('Solr config checksum verification disabled.')
Log.warn('Solr config checksum verification disabled: Solr may be offline or misconfigured')
end

ordered_plugin_backend_dirs = ASUtils.order_plugins(ASUtils.find_local_directories('backend'))
Expand Down
21 changes: 19 additions & 2 deletions backend/app/model/solr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
require 'advanced_search'

class Solr

class ChecksumMismatchError < StandardError; end

class NotFound < StandardError; end

module Checksums
def checksum_valid?
internal_checksum == external_checksum
Expand All @@ -20,7 +25,19 @@ def internal_checksum

def lookup_external_checksum
url = URI(File.join(@url, @path))
@external_checksum = Digest::SHA2.hexdigest(Net::HTTP.get_response(url).body)
response = Net::HTTP.get_response(url)
if response.code == '200'
@external_checksum = Digest::SHA2.hexdigest(response.body)
else
# if we made it this far, solr (or another server) is probably there
# but cannot find the documents we want, most likely because the core
# has not been set up correctly.
message = "Status #{response.code} when trying to verify #{@url}"
if response.body
message += "Server response:\n#{response.body}"
end
raise NotFound.new(message)
end
end

def lookup_internal_checksum
Expand Down Expand Up @@ -76,7 +93,7 @@ def self.verify_checksums!
def self.verify_checksum!(config)
return true if config.checksum_valid?

raise "Solr checksum verification failed (#{config.name}): expected [#{config.internal_checksum}] got [#{config.external_checksum}]"
raise ChecksumMismatchError.new "Solr checksum verification failed (#{config.name}): expected [#{config.internal_checksum}] got [#{config.external_checksum}]"
end

class Query
Expand Down
42 changes: 27 additions & 15 deletions backend/spec/model_solr_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -210,28 +210,40 @@ def response.code; '200'; end
end

describe 'Checksums' do
let(:schema) { Solr::Schema.new(AppConfig[:solr_url]) }
let(:solrconfig) { Solr::Solrconfig.new(AppConfig[:solr_url]) }
let(:response) { instance_double(Net::HTTPResponse) }

it 'will be valid when the internal and external checksums match' do
expect(schema.checksum_valid?).to be true
expect(solrconfig.checksum_valid?).to be true
def solrfile(file)
File.read(File.join(*[ ASUtils.find_base_directory, 'solr', file]))
end

it 'will be invalid when the external checksums do not match' do
allow(schema).to receive(:external_checksum) { 'nope' }
allow(solrconfig).to receive(:external_checksum) { "this_aint'it" }
it 'will be valid when the internal and external checksums match' do
allow(response).to receive(:code).and_return('200')
allow(response).to receive(:body).and_return(solrfile('schema.xml'), solrfile('solrconfig.xml'))
allow(Net::HTTP).to receive(:get_response).and_return(response)
expect { Solr.verify_checksums! }.not_to raise_error
end

expect(schema.checksum_valid?).to be false
expect(solrconfig.checksum_valid?).to be false
it 'will be invalid when the schema checksum does not match' do
allow(response).to receive(:code).and_return('200')
bad_schema = solrfile('schema.xml').sub('archivesspace', 'example')
allow(response).to receive(:body).and_return(bad_schema, solrfile('solrconfig.xml'))
allow(Net::HTTP).to receive(:get_response).and_return(response)
expect { Solr.verify_checksums! }.to raise_error(Solr::ChecksumMismatchError)
end

it 'will be invalid when the internal checksums do not match' do
allow(schema).to receive(:internal_checksum) { 'nope' }
allow(solrconfig).to receive(:internal_checksum) { "this_aint'it" }
it 'will be invalid when the config checksum does not match' do
allow(response).to receive(:code).and_return('200')
bad_config = solrfile('solrconfig.xml').sub('solr', 'foobar')
allow(response).to receive(:body).and_return(solrfile('schema.xml'), bad_config)
allow(Net::HTTP).to receive(:get_response).and_return(response)
expect { Solr.verify_checksums! }.to raise_error(Solr::ChecksumMismatchError)
end

expect(schema.checksum_valid?).to be false
expect(solrconfig.checksum_valid?).to be false
it 'will raise an error when the solr server returns a 404' do
allow(response).to receive(:code).and_return('404')
allow(response).to receive(:body).and_return("NOT FOUND")
allow(Net::HTTP).to receive(:get_response).and_return(response)
expect { Solr.verify_checksums! }.to raise_error(Solr::NotFound)
end
end

Expand Down