phi_attrs 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/publish.yml +28 -0
- data/lib/phi_attrs/phi_record.rb +87 -28
- data/lib/phi_attrs/rspec.rb +43 -0
- data/lib/phi_attrs/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c95e0078a0816fa79591bab794e8c423d70d8792354cbb09cb69cda60b93d4b
|
4
|
+
data.tar.gz: 7af031bbc1cc1aa2ba308dc778611b590faf33b4e572e9e264477dde4fb24ace
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a13b688097f56ad46044a7da0f91402565e582383e80f522f6ef3829fc75e677a5518a3190e261114713177ab6ab746783eb10bec4cc83215cf8089ca17cbc35
|
7
|
+
data.tar.gz: 323f3337e8d687e5e8e781324fd284008344a9ee8c15ff737840b736908face774331b762783076ffd5bb9e37a150452e4d712129a4a30fc169a33edde3abec9
|
@@ -0,0 +1,28 @@
|
|
1
|
+
name: Publish Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- "main"
|
7
|
+
tags:
|
8
|
+
- v*
|
9
|
+
jobs:
|
10
|
+
build:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v2
|
15
|
+
- uses: actions/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: '2.6'
|
18
|
+
- name: Install dependencies
|
19
|
+
run: |
|
20
|
+
gem install bundler:2.1.4
|
21
|
+
bundle install
|
22
|
+
- name: Release Gem
|
23
|
+
if: contains(github.ref, 'refs/tags/v')
|
24
|
+
uses: cadwallion/publish-rubygems-action@master
|
25
|
+
env:
|
26
|
+
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
27
|
+
RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
|
28
|
+
RELEASE_COMMAND: bundle exec rake release
|
data/lib/phi_attrs/phi_record.rb
CHANGED
@@ -107,8 +107,32 @@ module PhiAttrs
|
|
107
107
|
# end
|
108
108
|
# # PHI Access Disallowed
|
109
109
|
#
|
110
|
-
def allow_phi(user_id = nil, reason = nil, allow_only: nil)
|
111
|
-
|
110
|
+
def allow_phi(user_id = nil, reason = nil, allow_only: nil, &block)
|
111
|
+
get_phi(user_id, reason, allow_only: allow_only, &block)
|
112
|
+
return
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
# Enable PHI access for any instance of this class in the block given only
|
117
|
+
# returning whatever the block returns.
|
118
|
+
#
|
119
|
+
# @param [String] user_id A unique identifier for the person accessing the PHI
|
120
|
+
# @param [String] reason The reason for accessing PHI
|
121
|
+
# @param [collection of PhiRecord] allow_only Specific PhiRecords to allow access to
|
122
|
+
# &block [block] The block in which PHI access is allowed for the class
|
123
|
+
#
|
124
|
+
# @example
|
125
|
+
# results = Foo.allow_phi('user@example.com', 'viewing patient record') do
|
126
|
+
# Foo.search(params)
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
# @example
|
130
|
+
# loaded_foo = Foo.allow_phi('user@example.com', 'exporting patient list', allow_only: list_of_foos) do
|
131
|
+
# Bar.find_by(foo: list_of_foos).include(:foo)
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
def get_phi(user_id = nil, reason = nil, allow_only: nil)
|
135
|
+
raise ArgumentError, 'block required' unless block_given?
|
112
136
|
|
113
137
|
if allow_only.present?
|
114
138
|
raise ArgumentError, 'allow_only must be iterable with each' unless allow_only.respond_to?(:each)
|
@@ -125,7 +149,7 @@ module PhiAttrs
|
|
125
149
|
allow_only.each { |t| t.allow_phi!(user_id, reason) }
|
126
150
|
end
|
127
151
|
|
128
|
-
yield if block_given?
|
152
|
+
result = yield if block_given?
|
129
153
|
|
130
154
|
__instances_with_extended_phi.each do |obj|
|
131
155
|
if frozen_instances.include?(obj)
|
@@ -143,6 +167,8 @@ module PhiAttrs
|
|
143
167
|
allow_only.each { |t| t.disallow_last_phi!(preserve_extensions: true) }
|
144
168
|
# We've handled any newly extended allowances ourselves above
|
145
169
|
end
|
170
|
+
|
171
|
+
result
|
146
172
|
end
|
147
173
|
|
148
174
|
# Explicitly disallow phi access in a specific area of code. This does not
|
@@ -335,17 +361,41 @@ module PhiAttrs
|
|
335
361
|
# end
|
336
362
|
# # PHI Access Disallowed Here
|
337
363
|
#
|
338
|
-
def allow_phi(user_id = nil, reason = nil)
|
339
|
-
|
364
|
+
def allow_phi(user_id = nil, reason = nil, &block)
|
365
|
+
get_phi(user_id, reason, &block)
|
366
|
+
return
|
367
|
+
end
|
368
|
+
|
369
|
+
|
370
|
+
# Enable PHI access for a single instance of this class inside the block.
|
371
|
+
# Returns whatever is returned from the block.
|
372
|
+
# Nested calls to get_phi will log once per nested call
|
373
|
+
#s
|
374
|
+
# @param [String] user_id A unique identifier for the person accessing the PHI
|
375
|
+
# @param [String] reason The reason for accessing PHI
|
376
|
+
# @yield The block in which phi access is allowed
|
377
|
+
#
|
378
|
+
# @return PHI
|
379
|
+
#
|
380
|
+
# @example
|
381
|
+
# foo = Foo.find(1)
|
382
|
+
# phi_data = foo.get_phi('user@example.com', 'viewing patient record') do
|
383
|
+
# foo.phi_field
|
384
|
+
# end
|
385
|
+
#
|
386
|
+
def get_phi(user_id = nil, reason = nil)
|
387
|
+
raise ArgumentError, 'block required' unless block_given?
|
340
388
|
|
341
389
|
extended_instances = @__phi_relations_extended.clone
|
342
390
|
allow_phi!(user_id, reason)
|
343
391
|
|
344
|
-
yield if block_given?
|
392
|
+
result = yield if block_given?
|
345
393
|
|
346
394
|
new_extensions = @__phi_relations_extended - extended_instances
|
347
395
|
disallow_last_phi!(preserve_extensions: true)
|
348
396
|
revoke_extended_phi!(new_extensions) if new_extensions.any?
|
397
|
+
|
398
|
+
result
|
349
399
|
end
|
350
400
|
|
351
401
|
# Revoke all PHI access for a single instance of this class.
|
@@ -412,6 +462,25 @@ module PhiAttrs
|
|
412
462
|
end
|
413
463
|
end
|
414
464
|
|
465
|
+
|
466
|
+
# The unique identifier for whom access has been allowed on this instance.
|
467
|
+
# This is what was passed in when PhiRecord#allow_phi! was called.
|
468
|
+
#
|
469
|
+
# @return [String] the user_id passed in to allow_phi!
|
470
|
+
#
|
471
|
+
def phi_allowed_by
|
472
|
+
phi_context[:user_id]
|
473
|
+
end
|
474
|
+
|
475
|
+
# The access reason for allowing access to this instance.
|
476
|
+
# This is what was passed in when PhiRecord#allow_phi! was called.
|
477
|
+
#
|
478
|
+
# @return [String] the reason passed in to allow_phi!
|
479
|
+
#
|
480
|
+
def phi_access_reason
|
481
|
+
phi_context[:reason]
|
482
|
+
end
|
483
|
+
|
415
484
|
# Whether PHI access is allowed for a single instance of this class
|
416
485
|
#
|
417
486
|
# @example
|
@@ -424,6 +493,18 @@ module PhiAttrs
|
|
424
493
|
!phi_context.nil? && phi_context[:phi_access_allowed]
|
425
494
|
end
|
426
495
|
|
496
|
+
# Require phi access. Raises an error pre-emptively if it has not been granted.
|
497
|
+
#
|
498
|
+
# @example
|
499
|
+
# def use_phi(patient_record)
|
500
|
+
# patient_record.require_phi!
|
501
|
+
# # ...use PHI Freely
|
502
|
+
# end
|
503
|
+
#
|
504
|
+
def require_phi!
|
505
|
+
raise PhiAccessException, 'PHI Access required, please call allow_phi or allow_phi! first' unless phi_allowed?
|
506
|
+
end
|
507
|
+
|
427
508
|
def reload
|
428
509
|
@__phi_relations_extended.clear
|
429
510
|
super
|
@@ -479,28 +560,6 @@ module PhiAttrs
|
|
479
560
|
@__phi_log_keys = [PHI_ACCESS_LOG_TAG, self.class.name, @__phi_log_id]
|
480
561
|
end
|
481
562
|
|
482
|
-
# The unique identifier for whom access has been allowed on this instance.
|
483
|
-
# This is what was passed in when PhiRecord#allow_phi! was called.
|
484
|
-
#
|
485
|
-
# @private
|
486
|
-
#
|
487
|
-
# @return [String] the user_id passed in to allow_phi!
|
488
|
-
#
|
489
|
-
def phi_allowed_by
|
490
|
-
phi_context[:user_id]
|
491
|
-
end
|
492
|
-
|
493
|
-
# The access reason for allowing access to this instance.
|
494
|
-
# This is what was passed in when PhiRecord#allow_phi! was called.
|
495
|
-
#
|
496
|
-
# @private
|
497
|
-
#
|
498
|
-
# @return [String] the reason passed in to allow_phi!
|
499
|
-
#
|
500
|
-
def phi_access_reason
|
501
|
-
phi_context[:reason]
|
502
|
-
end
|
503
|
-
|
504
563
|
def phi_context
|
505
564
|
instance_phi_context || class_phi_context
|
506
565
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rspec/expectations'
|
2
|
+
|
3
|
+
DO_NOT_SPECIFY = "do not specify `allowed_by` or `with_access_reason` for negated `allow_phi_access`"
|
4
|
+
|
5
|
+
RSpec::Matchers.define :allow_phi_access do
|
6
|
+
match do |result|
|
7
|
+
@allowed = result.phi_allowed?
|
8
|
+
@user_id_matches = @user_id.nil? || @user_id == result.phi_allowed_by
|
9
|
+
@reason_matches = @reason.nil? || @reason == result.phi_access_reason
|
10
|
+
|
11
|
+
@allowed && @user_id_matches && @reason_matches
|
12
|
+
end
|
13
|
+
|
14
|
+
match_when_negated do |result|
|
15
|
+
raise ArgumentError, DO_NOT_SPECIFY unless @user_id.nil? && @reason.nil?
|
16
|
+
|
17
|
+
!result.phi_allowed?
|
18
|
+
end
|
19
|
+
|
20
|
+
chain :allowed_by do |user_id|
|
21
|
+
@user_id = user_id
|
22
|
+
end
|
23
|
+
|
24
|
+
chain :with_access_reason do |reason|
|
25
|
+
@reason = reason
|
26
|
+
end
|
27
|
+
|
28
|
+
# :nocov:
|
29
|
+
failure_message do |result|
|
30
|
+
msgs = []
|
31
|
+
|
32
|
+
msgs = ['PHI Access was not allowed.'] unless @allowed
|
33
|
+
msgs << "PHI Access was allowed by '#{result.phi_allowed_by}' (not '#{@user_id}')." unless @user_id_matches
|
34
|
+
msgs << "PHI Access was allowed because '#{result.phi_access_reason}' (not because '#{@reason}')." unless @reason_matches
|
35
|
+
|
36
|
+
msgs.join "\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
failure_message_when_negated do |result|
|
40
|
+
"PHI access was allowed by '#{result.phi_allowed_by}', because '#{result.phi_access_reason}'"
|
41
|
+
end
|
42
|
+
# :nocov:
|
43
|
+
end
|
data/lib/phi_attrs/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phi_attrs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wyatt Kirby
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -228,6 +228,7 @@ extensions: []
|
|
228
228
|
extra_rdoc_files: []
|
229
229
|
files:
|
230
230
|
- ".github/workflows/build.yml"
|
231
|
+
- ".github/workflows/publish.yml"
|
231
232
|
- ".gitignore"
|
232
233
|
- ".rspec"
|
233
234
|
- ".rubocop.yml"
|
@@ -259,6 +260,7 @@ files:
|
|
259
260
|
- lib/phi_attrs/logger.rb
|
260
261
|
- lib/phi_attrs/phi_record.rb
|
261
262
|
- lib/phi_attrs/railtie.rb
|
263
|
+
- lib/phi_attrs/rspec.rb
|
262
264
|
- lib/phi_attrs/version.rb
|
263
265
|
- phi_attrs.gemspec
|
264
266
|
homepage: http://www.apsis.io
|