strongmind-platform-sdk 3.27.0 → 3.27.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 810243f0c080ad6d0d3de344f35be529792ed8f8b46a2e26ec73d848cc2ec55b
4
- data.tar.gz: f194d6d594cd91f90dd5cb61ef73963d2616c8ed15ac34b5dfc976a2d37f14c2
3
+ metadata.gz: 021a46b4ab2f6bb6309de8a95199bfcbbce20a6f7840d8f019c36b748508e2d4
4
+ data.tar.gz: c70de4fb236c35ebafbe6aa6d46480fb7fcf9e44b81a4c84a66a38c8d15f1a7e
5
5
  SHA512:
6
- metadata.gz: 0f8a9dcb3b3084e352f3dcac40ca9f2cc59ef951e8124483ac06790cd065f555a25f08b4018bc74d7e77b06083683783bf0e8cbf000f1af1a37f55f85fb0c022
7
- data.tar.gz: 77cfa7f41f67166ff0107134aaf07ca0d44d3075cb44fd4c12ccb3f4903fe9ae117acc90f2530f28e99090b724f1cbb6d28dec23fe881fbbcd358cf8457a9f7a
6
+ metadata.gz: 9d29eba2b361d1f35683fc3b3f37bb39829a7c8505a71516d6e3e44f3ceb681cd5db59b3522640ab4682c88551062a75ddfe6985a04df7f475edaaf25773648e
7
+ data.tar.gz: d369c0b967a2e1bbcc0742507f9bd25bf3da167a38694c516d62618998047c0d849c7959601d919e9becdb14998ff305713f4cc665c7fab7763974913b72cbab
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/parameter_filter'
4
+ require_relative '../pii'
5
+
6
+ module PlatformSdk
7
+ module Logging
8
+ # Scrubs PII from stdout
9
+ class PiiFormatter
10
+ attr_reader :original_formatter
11
+
12
+ def initialize(original_formatter:, additional_fields: [])
13
+ @original_formatter = original_formatter
14
+ fields = Pii::DEFAULT_FIELDS + additional_fields
15
+ @param_filter = ActiveSupport::ParameterFilter.new(
16
+ fields, mask: Pii::FILTERED
17
+ )
18
+ end
19
+
20
+ def call(severity, timestamp, progname, message)
21
+ scrubbed = scrub_message(message)
22
+ @original_formatter.call(severity, timestamp, progname, scrubbed)
23
+ end
24
+
25
+ private
26
+
27
+ def scrub_message(message)
28
+ case message
29
+ when Hash
30
+ @param_filter.filter(message)
31
+ when String
32
+ Pii::PII_PATTERNS.reduce(message) do |msg, pattern|
33
+ msg.gsub(pattern, Pii::FILTERED)
34
+ end
35
+ else
36
+ message
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'logging/pii_formatter'
4
+
5
+ module PlatformSdk
6
+ # Wraps logging with built-in PII protection
7
+ module Logging
8
+ def self.apply_pii_protection(additional_fields: [])
9
+ logger = Rails.logger
10
+ return if logger.formatter.is_a?(PiiFormatter)
11
+
12
+ logger.formatter = PiiFormatter.new(
13
+ original_formatter: logger.formatter,
14
+ additional_fields:
15
+ )
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformSdk
4
+ module Pii
5
+ DEFAULT_FIELDS = [
6
+ :email, /\Aname\z/i, :first_name, :last_name, :student_name, :username,
7
+ :phone, :phone_number, :address, :street, :city, :zip, :postal_code,
8
+ :ssn, :social_security, :date_of_birth, :dob, :birthday,
9
+ :ip_address, /\Aip\z/i, :remote_ip,
10
+ :password, :password_confirmation, :token, :secret, :api_key,
11
+ :authorization
12
+ ].freeze
13
+
14
+ FILTERED = '[FILTERED]'
15
+
16
+ EMAIL_REGEX = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/
17
+ SSN_REGEX = /\b\d{3}-\d{2}-\d{4}\b/
18
+ PHONE_REGEX = /(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/
19
+
20
+ PII_PATTERNS = [EMAIL_REGEX, SSN_REGEX, PHONE_REGEX].freeze
21
+ end
22
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/parameter_filter'
4
+ require_relative '../pii'
5
+
6
+ module PlatformSdk
7
+ module Sentry
8
+ # Scrubs PII from Sentry events
9
+ class PiiScrubber
10
+ DEFAULT_PII_FIELDS = Pii::DEFAULT_FIELDS
11
+ FILTERED = Pii::FILTERED
12
+
13
+ attr_reader :filter
14
+
15
+ def initialize(additional_fields: [])
16
+ fields = DEFAULT_PII_FIELDS + additional_fields
17
+ @filter = ActiveSupport::ParameterFilter.new(fields, mask: FILTERED)
18
+ end
19
+
20
+ def scrub_hash(hash)
21
+ return {} unless hash.is_a?(Hash)
22
+
23
+ filter.filter(hash)
24
+ end
25
+
26
+ def scrub_event(event)
27
+ scrub_event_data(event)
28
+ scrub_request(event.request) if event.request
29
+ event
30
+ end
31
+
32
+ EMAIL_REGEX = Pii::EMAIL_REGEX
33
+
34
+ def scrub_breadcrumb(breadcrumb)
35
+ breadcrumb.data = scrub_hash(breadcrumb.data) if breadcrumb.data.is_a?(Hash)
36
+ breadcrumb.message = scrub_message(breadcrumb.message) if breadcrumb.message
37
+
38
+ breadcrumb
39
+ end
40
+
41
+ private
42
+
43
+ def scrub_message(message)
44
+ message.gsub(EMAIL_REGEX, FILTERED)
45
+ end
46
+
47
+ def scrub_user(user_hash)
48
+ id = user_hash[:id] || user_hash['id']
49
+ scrubbed = scrub_hash(user_hash)
50
+ scrubbed[:id] = id if user_hash.key?(:id)
51
+ scrubbed['id'] = id if user_hash.key?('id')
52
+ scrubbed
53
+ end
54
+
55
+ def scrub_request(request)
56
+ request.data = scrub_hash(request.data) if request.data.is_a?(Hash)
57
+ request.headers = scrub_hash(request.headers) if request.headers.is_a?(Hash)
58
+ request.query_string = FILTERED if request.query_string
59
+ request.cookies = FILTERED if request.cookies
60
+ end
61
+
62
+ def scrub_event_data(event)
63
+ event.user = scrub_user(event.user) if event.user.is_a?(Hash)
64
+ event.extra = scrub_hash(event.extra) if event.extra.is_a?(Hash)
65
+ event.contexts = scrub_hash(event.contexts) if event.contexts.is_a?(Hash)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,7 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'sentry/pii_scrubber'
4
+
3
5
  module PlatformSdk
4
6
  module Sentry
7
+ def self.apply_pii_protection(config, additional_fields: [])
8
+ config.send_default_pii = false
9
+ config.include_local_variables = false
10
+
11
+ scrubber = PiiScrubber.new(additional_fields: additional_fields)
12
+
13
+ config.before_send = lambda do |event, _hint|
14
+ scrubber.scrub_event(event)
15
+ end
16
+
17
+ config.before_breadcrumb = lambda do |breadcrumb, _hint|
18
+ scrubber.scrub_breadcrumb(breadcrumb)
19
+ end
20
+
21
+ config.before_send_transaction = lambda do |event, _hint|
22
+ return nil if sentry_ignored(event)
23
+
24
+ scrubber.scrub_event(event)
25
+ end
26
+ end
27
+
5
28
  def self.sentry_ignored(event, ignored_urls = sentry_ignored_urls)
6
29
  return false if event.transaction_info[:source] != :url
7
30
  return true if ignored_urls.any? { |url| event.transaction.match?(url) }
@@ -3,7 +3,7 @@
3
3
  module PlatformSdk
4
4
  MAJOR = 3
5
5
  MINOR = 27
6
- PATCH = 0
6
+ PATCH = 2
7
7
 
8
8
  VERSION = "#{PlatformSdk::MAJOR}.#{PlatformSdk::MINOR}.#{PlatformSdk::PATCH}"
9
9
  end
data/lib/platform_sdk.rb CHANGED
@@ -1,32 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "platform_sdk/version"
4
- require "platform_sdk/one_roster"
5
- require "platform_sdk/identity"
6
- require "platform_sdk/power_school"
7
- require "platform_sdk/aws"
8
- require "platform_sdk/id_mapper"
9
- require "platform_sdk/edkey"
10
- require "platform_sdk/data_pipeline"
11
- require "platform_sdk/pencil_spaces"
12
- require "platform_sdk/edfi"
13
- require "platform_sdk/sentry"
14
- require "platform_sdk/learnosity_api"
15
- require "platform_sdk/canvas_api"
16
- require "platform_sdk/bynder"
17
- require "platform_sdk/events"
18
- require "platform_sdk/central"
19
- require "platform_sdk/active_record/data_pipelineable"
20
- require "platform_sdk/spec_support"
21
- require "asset_sync"
22
- require "fog-aws"
23
- require "platform_sdk/asset_sync_initializer"
24
- require "platform_sdk/sidekiq/ecs_task_protection_middleware"
25
- require "platform_sdk/sidekiq"
26
- require "platform_sdk/jobs/send_noun_to_pipeline_job"
27
- require "platform_sdk/jira"
28
- require "platform_sdk/catalog_manager"
29
- require "platform_sdk/llm_gateway"
3
+ require_relative 'platform_sdk/version'
4
+ require 'platform_sdk/one_roster'
5
+ require 'platform_sdk/identity'
6
+ require 'platform_sdk/power_school'
7
+ require 'platform_sdk/aws'
8
+ require 'platform_sdk/id_mapper'
9
+ require 'platform_sdk/edkey'
10
+ require 'platform_sdk/data_pipeline'
11
+ require 'platform_sdk/pencil_spaces'
12
+ require 'platform_sdk/edfi'
13
+ require 'platform_sdk/pii'
14
+ require 'platform_sdk/sentry'
15
+ require 'platform_sdk/logging'
16
+ require 'platform_sdk/learnosity_api'
17
+ require 'platform_sdk/canvas_api'
18
+ require 'platform_sdk/bynder'
19
+ require 'platform_sdk/events'
20
+ require 'platform_sdk/central'
21
+ require 'platform_sdk/active_record/data_pipelineable'
22
+ require 'platform_sdk/spec_support'
23
+ require 'asset_sync'
24
+ require 'fog-aws'
25
+ require 'platform_sdk/asset_sync_initializer'
26
+ require 'platform_sdk/sidekiq/ecs_task_protection_middleware'
27
+ require 'platform_sdk/sidekiq'
28
+ require 'platform_sdk/jobs/send_noun_to_pipeline_job'
29
+ require 'platform_sdk/jira'
30
+ require 'platform_sdk/catalog_manager'
31
+ require 'platform_sdk/llm_gateway'
30
32
 
31
33
  module PlatformSdk
32
34
  class Error < StandardError; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strongmind-platform-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.27.0
4
+ version: 3.27.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Platform Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-03 00:00:00.000000000 Z
11
+ date: 2026-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -284,6 +284,8 @@ files:
284
284
  - lib/platform_sdk/learnosity_api/client.rb
285
285
  - lib/platform_sdk/llm_gateway.rb
286
286
  - lib/platform_sdk/llm_gateway/client.rb
287
+ - lib/platform_sdk/logging.rb
288
+ - lib/platform_sdk/logging/pii_formatter.rb
287
289
  - lib/platform_sdk/one_roster.rb
288
290
  - lib/platform_sdk/one_roster/client.rb
289
291
  - lib/platform_sdk/ops_genie.rb
@@ -293,10 +295,12 @@ files:
293
295
  - lib/platform_sdk/pencil_spaces/constants.rb
294
296
  - lib/platform_sdk/pencil_spaces/models.rb
295
297
  - lib/platform_sdk/pencil_spaces/models/user_with_role.rb
298
+ - lib/platform_sdk/pii.rb
296
299
  - lib/platform_sdk/power_school.rb
297
300
  - lib/platform_sdk/power_school/client.rb
298
301
  - lib/platform_sdk/power_school/special_program.rb
299
302
  - lib/platform_sdk/sentry.rb
303
+ - lib/platform_sdk/sentry/pii_scrubber.rb
300
304
  - lib/platform_sdk/sidekiq.rb
301
305
  - lib/platform_sdk/sidekiq/ecs_task_protection_middleware.rb
302
306
  - lib/platform_sdk/spec_support.rb