Skip to content

Commit

Permalink
Replace usage of Audit with Fixity check
Browse files Browse the repository at this point in the history
This will potentially reduce confusion, because Fedora has an Audit that
is different from a fixity check.

Fixes #187
  • Loading branch information
jcoyne committed Apr 5, 2017
1 parent 523706c commit 79e0600
Show file tree
Hide file tree
Showing 28 changed files with 269 additions and 258 deletions.
2 changes: 1 addition & 1 deletion .rubocop_todo.yml
Expand Up @@ -159,7 +159,7 @@ RSpec/AnyInstance:
- 'spec/lib/hyrax/arkivo/actor_spec.rb'
- 'spec/presenters/hyrax/work_usage_spec.rb'
- 'spec/presenters/hyrax/file_usage_spec.rb'
- 'spec/services/hyrax/repository_audit_service_spec.rb'
- 'spec/services/hyrax/repository_fixity_check_service_spec.rb'
- 'spec/services/hyrax/workflow/permission_generator_spec.rb'
- 'spec/services/hyrax/workflow/sipity_actions_generator_spec.rb'
- 'spec/services/hyrax/workflow/state_machine_generator_spec.rb'
Expand Down
Expand Up @@ -23,7 +23,7 @@ module CollectionsControllerBehavior
# Catch permission errors
rescue_from Hydra::AccessDenied, CanCan::AccessDenied, with: :deny_collection_access

# actions: audit, index, create, new, edit, show, update, destroy, permissions, citation
# actions: index, create, new, edit, show, update, destroy, permissions, citation
before_action :authenticate_user!, except: [:show, :index]
load_and_authorize_resource except: [:index, :show, :create], instance_name: :collection

Expand Down
16 changes: 0 additions & 16 deletions app/controllers/hyrax/audits_controller.rb

This file was deleted.

16 changes: 16 additions & 0 deletions app/controllers/hyrax/fixity_checks_controller.rb
@@ -0,0 +1,16 @@
module Hyrax
class FixityChecksController < ApplicationController
before_action :authenticate_user!

def create
render json: fixity_check_service.fixity_check
end

protected

def fixity_check_service
file_set = ::FileSet.find(params[:file_set_id])
FileSetFixityCheckService.new(file_set)
end
end
end
16 changes: 8 additions & 8 deletions app/jobs/audit_job.rb → app/jobs/fixity_check_job.rb
@@ -1,28 +1,28 @@
class AuditJob < ActiveJob::Base
# URI of the resource to audit.
# This URI could include the actual resource (e.g. content) and the version to audit:
class FixityCheckJob < ActiveJob::Base
# URI of the resource to check fixity for.
# This URI could include the actual resource (e.g. content) and the version to fixity check:
# http://localhost:8983/fedora/rest/test/a/b/c/abcxyz/content/fcr:versions/version1
# but it could also just be:
# http://localhost:8983/fedora/rest/test/a/b/c/abcxyz/content
# @param [FileSet] file_set - the parent object
# @param [String] file_id - used to find the file within its parent object (usually "original_file")
# @param [String] uri - of the specific file/version to be audited
# @param [String] uri - of the specific file/version to fixity check
def perform(file_set, file_id, uri)
log = run_audit(file_set, file_id, uri)
log = run_check(file_set, file_id, uri)
fixity_ok = log.pass == 1
unless fixity_ok
if Hyrax.config.callback.set?(:after_audit_failure)
if Hyrax.config.callback.set?(:after_fixity_check_failure)
login = file_set.depositor
user = User.find_by_user_key(login)
Hyrax.config.callback.run(:after_audit_failure, file_set, user, log.created_at)
Hyrax.config.callback.run(:after_fixity_check_failure, file_set, user, log.created_at)
end
end
fixity_ok
end

protected

def run_audit(file_set, file_id, uri)
def run_check(file_set, file_id, uri)
begin
fixity_ok = ActiveFedora::FixityService.new(uri).check
rescue Ldp::NotFound
Expand Down
3 changes: 2 additions & 1 deletion app/models/checksum_audit_log.rb
@@ -1,5 +1,6 @@
class ChecksumAuditLog < ActiveRecord::Base
def self.get_audit_log(id, path, version_uri)
# TODO: this method doesn't seem to be used. Remove?
def self.fixity_check_log(id, path, version_uri)
ChecksumAuditLog.find_or_create_by(file_set_id: id, file_id: path, version: version_uri)
end

Expand Down
8 changes: 4 additions & 4 deletions app/presenters/hyrax/file_set_presenter.rb
Expand Up @@ -76,8 +76,8 @@ def event_class
solr_document.to_model.model_name.name
end

def audit_status
audit_service.logged_audit_status
def fixity_check_status
fixity_check_service.logged_fixity_status
end

def parent
Expand All @@ -89,8 +89,8 @@ def parent
current_ability).first
end

def audit_service
@audit_service ||= Hyrax::FileSetAuditService.new(id)
def fixity_check_service
@fixity_check_service ||= Hyrax::FileSetFixityCheckService.new(id)
end

private
Expand Down
122 changes: 0 additions & 122 deletions app/services/hyrax/file_set_audit_service.rb

This file was deleted.

124 changes: 124 additions & 0 deletions app/services/hyrax/file_set_fixity_check_service.rb
@@ -0,0 +1,124 @@
module Hyrax
class FileSetFixityCheckService
attr_reader :file_set, :id

# @param file_set [ActiveFedora::Base, String] file_set
def initialize(file_set)
if file_set.is_a?(String)
@id = file_set
else
@id = file_set.id
@file_set = file_set
end
end

NO_RUNS = 999

# provides a human readable version of the fixity check status
# This may trigger fixity checks if required
# @param [Hydra::PCDM::File] file the file to get the fixity check status for,
# defaults to the original_file.
def human_readable_fixity_check_status(file = file_set.original_file)
fixity_check_stat(file)
end

# Check the file by only what is in the fixity check log.
# Do not try to access the versions if we do not have access to them.
# Use this when a file_set is loaded from solr instead of fedora
def logged_fixity_status
fixity_results = ChecksumAuditLog.logs_for(id, "original_file")
.collect { |result| result["pass"] }

if !fixity_results.empty?
stat_to_string(fixity_results.reduce(true) { |sum, value| sum && value })
else
'Fixity checks have not yet been run on this file.'
end
end

# Fixity checks each version of each file if it hasn't been checked recently
# Returns the set of most recent fixity check status for each version of the
# content file
# @param [Hash] log container for messages, mapping file ids to status
def fixity_check(log = {})
file_set.files.each { |f| log[f.id] = fixity_check_file(f) }
log
end

private

def stat_to_string(stat)
case stat
when 0
'failing'
when 1
'passing'
else
raise ArgumentError, "Unknown status `#{stat}'"
end
end

# Retrieve or generate the fixity check for a file (all versions are checked for versioned files)
# @param [ActiveFedora::File] file to fixity check
# @param [Array] log container for messages
def fixity_check_file(file, log = [])
versions = file.has_versions? ? file.versions.all : file
versions.each { |v| log << fixity_check_file_version(file.id, v.uri) }
log
end

# Retrieve or generate the fixity check for a file and provide a human-readable status message.
# @param [ActiveFedora::File] file to fixity check
def fixity_check_stat(file)
fixity_results = fixity_check_file(file).collect { |result| result['pass'] }
# check how many non runs we had
non_runs = fixity_results.reduce(0) { |sum, value| value == NO_RUNS ? sum + 1 : sum }
build_fixity_check_stat_message(fixity_results, non_runs)
end

def build_fixity_check_stat_message(fixity_results, non_runs)
if non_runs.zero?
result = fixity_results.reduce(true) { |sum, value| sum && value }
stat_to_string(result)
elsif non_runs < fixity_results.length
result = fixity_results.reduce(true) { |sum, value| value == NO_RUNS ? sum : sum && value }
"Some fixity checks have not been run, but the ones run were #{stat_to_string(result)}."
else
'Fixity checks have not yet been run on this file.'
end
end
private :build_fixity_check_stat_message

# Retrieve or generate the fixity check for a specific version of a file
# @param [String] file_id used to find the file within its parent object (usually "original_file")
# @param [String] version_uri the version to be fixity checked (or the file uri for non-versioned files)
def fixity_check_file_version(file_id, version_uri)
latest_fixity_check = ChecksumAuditLog.logs_for(file_set.id, file_id).first
return latest_fixity_check unless needs_fixity_check?(latest_fixity_check)
FixityCheckJob.perform_later(file_set, file_id, version_uri.to_s)
latest_fixity_check || ChecksumAuditLog.new(pass: NO_RUNS, file_set_id: file_set.id, file_id: file_id, version: version_uri)
end

# Check if time since the last fixity check is greater than the maximum days allowed between fixity checks
# @param [ChecksumAuditLog] latest_fixity_check the most recent fixity check
def needs_fixity_check?(latest_fixity_check)
return true unless latest_fixity_check
unless latest_fixity_check.updated_at
logger.warn "***FIXITY*** problem with fixity check log! Latest Fixity check is not nil, but updated_at is not set #{latest_fixity_check}"
return true
end
days_since_last_fixity_check(latest_fixity_check) >= Hyrax.config.max_days_between_fixity_checks
end

# Return the number of days since the latest fixity check
# @param [ChecksumAuditLog] latest_fixity_check the most recent fixity check
def days_since_last_fixity_check(latest_fixity_check)
(DateTime.current - latest_fixity_check.updated_at.to_date).to_i
end

# Loads the FileSet from Fedora if needed
def file_set
@file_set ||= FileSet.find(id)
end
end
end
@@ -1,5 +1,5 @@
module Hyrax
class AuditFailureService < MessageUserService
class FixityCheckFailureService < MessageUserService
attr_reader :log_date

def initialize(file_set, user, log_date)
Expand All @@ -10,11 +10,11 @@ def initialize(file_set, user, log_date)
def message
uri = file_set.original_file.uri.to_s
file_title = file_set.title.first
"The audit run at #{log_date} for #{file_title} (#{uri}) failed."
"The fixity check run at #{log_date} for #{file_title} (#{uri}) failed."
end

def subject
'Failing Audit Run'
'Failing Fixity Check'
end
end
end
9 changes: 0 additions & 9 deletions app/services/hyrax/repository_audit_service.rb

This file was deleted.

0 comments on commit 79e0600

Please sign in to comment.