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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6271ebbfae4a5ddad7aa1ad27b812cc4056a5a4958b1067ddf2aa717975b738
4
- data.tar.gz: '098ec65389f50bbe24876657a1ff9eb78bbbe17fb5192804ebbc2f75eedd97f4'
3
+ metadata.gz: 0c95e0078a0816fa79591bab794e8c423d70d8792354cbb09cb69cda60b93d4b
4
+ data.tar.gz: 7af031bbc1cc1aa2ba308dc778611b590faf33b4e572e9e264477dde4fb24ace
5
5
  SHA512:
6
- metadata.gz: a5832351881d96019071f9b77ac4e08b991104dca6f47c8a1917f5c3546002d7510c5d0fe7ceaa4fe37df7006ec71105acbbcc99a5c9928e57e78b43a7cd2d5d
7
- data.tar.gz: 3a153bd1a992dbbb94de889f8a82c22f969dd1bb9b9f36254485d0265f70cba89d89f1c8b424e30056aa1c23c5b8e8be3142d7b5ccfed05c970ec67aa3614d69
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
@@ -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
- raise ArgumentError, 'block required. use allow_phi! without block' unless block_given?
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
- raise ArgumentError, 'block required. use allow_phi! without block' unless block_given?
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PhiAttrs
4
- VERSION = '0.2.1'
4
+ VERSION = '0.2.2'
5
5
  end
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.1
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-10 00:00:00.000000000 Z
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