foobara 0.0.81 → 0.0.84

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.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/projects/builtin_types/src/datetime/casters/seconds_since_epoch.rb +2 -2
  4. data/projects/command/src/transformed_command.rb +26 -7
  5. data/projects/command_connectors/src/command_connector.rb +10 -2
  6. data/projects/command_connectors/src/command_registry/exposed_command.rb +19 -20
  7. data/projects/command_connectors/src/command_registry/exposed_domain.rb +8 -13
  8. data/projects/command_connectors/src/command_registry/exposed_organization.rb +7 -12
  9. data/projects/command_connectors/src/command_registry.rb +25 -6
  10. data/projects/command_connectors/src/serializers/aggregate_serializer.rb +1 -1
  11. data/projects/detached_entity/lib/foobara/detached_entity.rb +1 -0
  12. data/projects/detached_entity/src/sensitive_value_removers/detached_entity.rb +8 -0
  13. data/projects/domain/src/domain_module_extension.rb +5 -1
  14. data/projects/entity/lib/foobara/entity.rb +1 -0
  15. data/projects/entity/src/sensitive_value_removers/entity.rb +20 -0
  16. data/projects/model/lib/foobara/model.rb +5 -0
  17. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/model_class_desugarizer.rb +5 -1
  18. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/to_type_transformer.rb +42 -11
  19. data/projects/model/src/sensitive_value_removers/model.rb +23 -0
  20. data/projects/namespace/src/is_namespace.rb +5 -3
  21. data/projects/persistence/src/entity_base/transaction.rb +1 -1
  22. data/projects/type_declarations/lib/foobara/type_declarations.rb +2 -0
  23. data/projects/type_declarations/src/remove_sensitive_values_transformer.rb +45 -0
  24. data/projects/type_declarations/src/sensitive_value_removers/array.rb +30 -0
  25. data/projects/type_declarations/src/sensitive_value_removers/attributes.rb +35 -0
  26. data/projects/type_declarations/src/type_declarations.rb +22 -0
  27. data/projects/type_declarations/src/with_registries.rb +5 -0
  28. data/projects/types/src/type.rb +18 -0
  29. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66f1d5b1015809a2646a0627b8d6af04bdca39257a21a361e5cb78807b0ba611
4
- data.tar.gz: 565397a74e404cdba4e629d2bb28b27dcb5b23f2e144a8dfeccac22690600a45
3
+ metadata.gz: a3398098145e12cd84209b6bf1b109b680a6d8edd55a1d5d0b47fcfcf1929fbc
4
+ data.tar.gz: 2077064836ce7d87e3afebc8d38677558b9f6ab70043e4cd839a5497159e1716
5
5
  SHA512:
6
- metadata.gz: 42b0474e8712dfc36495379cd12d61b7c6aee754382cce807a330038d5fd249ebfe3bc4f7b503d0a1d80b92c12b67ab1297007d3535e9983e9ae1a116e8bd31b
7
- data.tar.gz: a12f6239df09e306ee8a1587f56e74cce4d9bfc78393daeb648b82c91f0d07806ba8e5ebec48b80f4f77e4e956e82667d7b95b0448367a7b5c1ae4d862380a3a
6
+ metadata.gz: c7e666a31c5b406fa4fdb3adce913a7417230de51b4d7f60235aecfd6a3b5814900c85f48f4f06d801b1eddf89bf2b4c3ece67d9c90517fe719e2659e83f4b12
7
+ data.tar.gz: 270cbcd61d4b77128e32b7bab9a056ed5f95a3132f40f000166b2f911bfd0dfaae58ec25fedc3641b4c73d0440d23d79f6ec56e7e8bb2d83a1f5b30f218f3ee8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # [0.0.84] - 2025-03-22
2
+
3
+ - Remove sensitive values from command connector results
4
+ - Allow creating models in two different namespace trees and use this is the command connector
5
+ - Use real domains/orgs in command connectors, eliminating ExposedDomain/Org concept
6
+ - Allow Datetime to be cast from a float
7
+
8
+ # [0.0.82] - 2025-03-21
9
+
10
+ - Fix bug incorrectly creating model classes in Foobara::GlobalDomain module
11
+
1
12
  # [0.0.81] - 2025-03-21
2
13
 
3
14
  - No longer automatically creates Foobara::Model classes when creating a foobara model type via type declaration
@@ -4,11 +4,11 @@ module Foobara
4
4
  module Casters
5
5
  class SecondsSinceEpoch < Value::Caster
6
6
  def applicable?(value)
7
- value.is_a?(::Integer)
7
+ value.is_a?(::Integer) || value.is_a?(::Float)
8
8
  end
9
9
 
10
10
  def applies_message
11
- "be a an integer representing seconds since epoch"
11
+ "be a an integer or float representing seconds since epoch"
12
12
  end
13
13
 
14
14
  def cast(seconds_since_epoch)
@@ -19,6 +19,7 @@ module Foobara
19
19
 
20
20
  def subclass(
21
21
  command_class,
22
+ scoped_namespace:,
22
23
  full_command_name:,
23
24
  command_name:,
24
25
  inputs_transformers:,
@@ -32,6 +33,22 @@ module Foobara
32
33
  suffix: nil,
33
34
  capture_unknown_error: false
34
35
  )
36
+ result_type = command_class.result_type
37
+
38
+ if result_type&.has_sensitive_types?
39
+ remover_class = Foobara::TypeDeclarations.sensitive_value_remover_class_for_type(result_type)
40
+
41
+ remover = Namespace.use scoped_namespace do
42
+ transformed_result_type = result_type_from_transformers(result_type, result_transformers)
43
+
44
+ remover_class.new(transformed_result_type).tap do |r|
45
+ r.scoped_path = ["SensitiveValueRemover", *transformed_result_type.scoped_full_path]
46
+ end
47
+ end
48
+
49
+ result_transformers = [*result_transformers, remover]
50
+ end
51
+
35
52
  Class.new(self).tap do |klass|
36
53
  klass.command_class = command_class
37
54
  klass.command_name = command_name
@@ -67,18 +84,20 @@ module Foobara
67
84
  type
68
85
  end
69
86
 
70
- def result_type
71
- type = command_class.result_type
72
-
73
- result_transformers.each do |transformer|
87
+ def result_type_from_transformers(result_type, transformers)
88
+ Util.array(transformers).each do |transformer|
74
89
  if transformer.is_a?(Class) && transformer < TypeDeclarations::TypedTransformer
75
- new_type = transformer.type(type)
90
+ new_type = transformer.type(result_type)
76
91
 
77
- type = new_type if new_type
92
+ result_type = new_type if new_type
78
93
  end
79
94
  end
80
95
 
81
- type
96
+ result_type
97
+ end
98
+
99
+ def result_type
100
+ result_type_from_transformers(command_class.result_type, result_transformers)
82
101
  end
83
102
 
84
103
  def error_context_type_map
@@ -357,7 +357,11 @@ module Foobara
357
357
  # Drive all of this off of the list of exposed commands...
358
358
  to_include = Set.new
359
359
 
360
- command_registry.foobara_each do |exposed_whatever|
360
+ to_include << command_registry.global_organization
361
+ to_include << command_registry.global_domain
362
+
363
+ # ABSOLUTE lets us get all of the children but not include dependent domains (GlobalDomain)
364
+ command_registry.foobara_each(mode: Namespace::LookupMode::ABSOLUTE) do |exposed_whatever|
361
365
  to_include << exposed_whatever
362
366
  end
363
367
 
@@ -408,7 +412,11 @@ module Foobara
408
412
 
409
413
  category_symbol = command_registry.foobara_category_symbol_for(object)
410
414
 
411
- raise "no category symbol for #{object}" unless category_symbol
415
+ unless category_symbol
416
+ # :nocov:
417
+ raise "no category symbol for #{object}"
418
+ # :nocov:
419
+ end
412
420
 
413
421
  namespace = if object.is_a?(Types::Type)
414
422
  object.created_in_namespace
@@ -94,26 +94,7 @@ module Foobara
94
94
  @full_command_symbol ||= Util.underscore_sym(full_command_name)
95
95
  end
96
96
 
97
- def root_registry
98
- parent = scoped_namespace
99
- parent = parent.scoped_namespace while parent.scoped_namespace
100
- parent
101
- end
102
-
103
97
  def foobara_manifest(to_include: Set.new, remove_sensitive: true)
104
- # A bit of a hack here. We don't have an exposed type class to encapsulate including exposed domains/orgs
105
- # which leads to a bug when a global command is exposed that depends on a type in a non-global domain
106
- # but there being no other reason to include that non-global domain.
107
- transformed_command_class.types_depended_on(remove_sensitive:).select(&:registered?).each do |type|
108
- full_domain_name = type.foobara_domain.scoped_full_name
109
-
110
- unless root_registry.foobara_lookup_domain(full_domain_name)
111
- exposed_domain = root_registry.build_and_register_exposed_domain(full_domain_name)
112
- to_include << exposed_domain
113
- to_include << exposed_domain.foobara_organization
114
- end
115
- end
116
-
117
98
  transformed_command_class.foobara_manifest(to_include:, remove_sensitive:).merge(super).merge(
118
99
  Util.remove_blank(
119
100
  scoped_category: :command,
@@ -133,13 +114,15 @@ module Foobara
133
114
  serializers,
134
115
  allowed_rule,
135
116
  requires_authentication,
136
- authenticator
117
+ authenticator,
118
+ result_has_sensitive_types?
137
119
  ]
138
120
  ) && scoped_path == command_class.scoped_path
139
121
  command_class
140
122
  else
141
123
  Foobara::TransformedCommand.subclass(
142
124
  command_class,
125
+ scoped_namespace:,
143
126
  full_command_name:,
144
127
  command_name:,
145
128
  capture_unknown_error:,
@@ -154,6 +137,22 @@ module Foobara
154
137
  )
155
138
  end
156
139
  end
140
+
141
+ # TODO: what to do if the whole return type is sensitive? return nil?
142
+ def result_has_sensitive_types?
143
+ result_type = command_class.result_type
144
+
145
+ if result_type.nil?
146
+ false
147
+ elsif result_type.sensitive?
148
+ # :nocov:
149
+ # TODO: we should convert it to nil I suppose
150
+ raise "Not sure yet how to handle a sensitive result type hmmmm..."
151
+ # :nocov:
152
+ else
153
+ command_class.result_type.has_sensitive_types?
154
+ end
155
+ end
157
156
  end
158
157
  end
159
158
  end
@@ -1,23 +1,18 @@
1
1
  module Foobara
2
2
  class CommandRegistry
3
- class ExposedDomain
4
- foobara_instances_are_namespaces!
3
+ module ExposedDomain
4
+ attr_reader :unexposed_domain
5
5
 
6
- include TruncatedInspect
7
- include IsManifestable
8
-
9
- attr_accessor :domain_module
10
-
11
- def initialize(domain_module)
12
- self.domain_module = domain_module
13
- self.scoped_path = domain_module.scoped_path
6
+ def unexposed_domain=(unexposed_domain)
7
+ @unexposed_domain = unexposed_domain
8
+ self.scoped_path = unexposed_domain.scoped_path
14
9
  end
15
10
 
16
11
  # TODO: unable to address types here so it is handled as a hack higher up...
17
12
  def foobara_manifest(to_include: Set.new, remove_sensitive: true)
18
13
  to_include << foobara_organization
19
14
 
20
- domain_manifest = domain_module.foobara_manifest(to_include: Set.new, remove_sensitive:)
15
+ domain_manifest = unexposed_domain.foobara_manifest(to_include: Set.new, remove_sensitive:)
21
16
  mode = Foobara::Namespace::LookupMode::DIRECT
22
17
  commands = foobara_all_command(mode:).map(&:foobara_manifest_reference).sort
23
18
 
@@ -25,7 +20,7 @@ module Foobara
25
20
  end
26
21
 
27
22
  def foobara_organization
28
- full_org_name = domain_module.foobara_organization.scoped_full_name
23
+ full_org_name = unexposed_domain.foobara_organization.scoped_full_name
29
24
  root_registry.foobara_lookup_organization(full_org_name)
30
25
  end
31
26
 
@@ -36,7 +31,7 @@ module Foobara
36
31
  end
37
32
 
38
33
  def foobara_manifest_reference
39
- domain_module.foobara_manifest_reference
34
+ unexposed_domain.foobara_manifest_reference
40
35
  end
41
36
  end
42
37
  end
@@ -1,21 +1,16 @@
1
1
  module Foobara
2
2
  class CommandRegistry
3
- class ExposedOrganization
4
- foobara_instances_are_namespaces!
3
+ module ExposedOrganization
4
+ attr_reader :unexposed_organization
5
5
 
6
- include TruncatedInspect
7
- include IsManifestable
8
-
9
- attr_accessor :organization_module
10
-
11
- def initialize(organization_module)
12
- self.organization_module = organization_module
13
- self.scoped_path = organization_module.scoped_path
6
+ def unexposed_organization=(unexposed_organization)
7
+ @unexposed_organization = unexposed_organization
8
+ self.scoped_path = unexposed_organization.scoped_path
14
9
  end
15
10
 
16
11
  # TODO: unable to address types here so it is handled as a hack higher up...
17
12
  def foobara_manifest(to_include: Set.new, remove_sensitive: true)
18
- organization_manifest = organization_module.foobara_manifest(to_include: Set.new, remove_sensitive:)
13
+ organization_manifest = unexposed_organization.foobara_manifest(to_include: Set.new, remove_sensitive:)
19
14
  mode = Foobara::Namespace::LookupMode::DIRECT
20
15
  domains = foobara_all_domain(mode:).map(&:foobara_manifest_reference).sort
21
16
 
@@ -23,7 +18,7 @@ module Foobara
23
18
  end
24
19
 
25
20
  def foobara_manifest_reference
26
- organization_module.foobara_manifest_reference
21
+ unexposed_organization.foobara_manifest_reference
27
22
  end
28
23
  end
29
24
  end
@@ -10,7 +10,7 @@ module Foobara
10
10
  self.scoped_path = []
11
11
  self.authenticator = authenticator
12
12
 
13
- customized = %i[command domain organization]
13
+ customized = %i[command]
14
14
 
15
15
  Namespace.global.foobara_categories.keys.reverse.each do |symbol|
16
16
  next if customized.include?(symbol)
@@ -21,8 +21,6 @@ module Foobara
21
21
  end
22
22
 
23
23
  foobara_add_category_for_instance_of(:command, ExposedCommand)
24
- foobara_add_category_for_instance_of(:domain, ExposedDomain)
25
- foobara_add_category_for_instance_of(:organization, ExposedOrganization)
26
24
  end
27
25
 
28
26
  def register(command_class, **)
@@ -67,7 +65,6 @@ module Foobara
67
65
  end
68
66
 
69
67
  def build_and_register_exposed_domain(domain_full_name)
70
- # TODO: would be nice to not have to do this...
71
68
  domain_module = if domain_full_name.to_s == ""
72
69
  GlobalDomain
73
70
  else
@@ -78,7 +75,13 @@ module Foobara
78
75
  exposed_organization = foobara_lookup_organization(full_organization_name) ||
79
76
  build_and_register_exposed_organization(full_organization_name)
80
77
 
81
- exposed_domain = ExposedDomain.new(domain_module)
78
+ exposed_domain = Module.new
79
+ exposed_domain.foobara_namespace!
80
+ exposed_domain.foobara_domain!
81
+ exposed_domain.extend(ExposedDomain)
82
+ exposed_domain.unexposed_domain = domain_module
83
+
84
+ exposed_domain.foobara_depends_on domain_module
82
85
 
83
86
  exposed_organization.foobara_register(exposed_domain)
84
87
  exposed_domain.foobara_parent_namespace = exposed_organization
@@ -86,6 +89,17 @@ module Foobara
86
89
  exposed_domain
87
90
  end
88
91
 
92
+ def global_domain
93
+ foobara_lookup_domain("") || build_and_register_exposed_domain("")
94
+ end
95
+
96
+ def global_organization
97
+ # TODO: test this
98
+ # :nocov:
99
+ foobara_lookup_organization("") || build_and_register_exposed_organization("")
100
+ # :nocov:
101
+ end
102
+
89
103
  def build_and_register_exposed_organization(full_organization_name)
90
104
  org = if full_organization_name.to_s == ""
91
105
  GlobalOrganization
@@ -93,7 +107,12 @@ module Foobara
93
107
  Namespace.global.foobara_lookup_organization!(full_organization_name)
94
108
  end
95
109
 
96
- exposed_organization = ExposedOrganization.new(org)
110
+ exposed_organization = Module.new
111
+ exposed_organization.foobara_namespace!
112
+ exposed_organization.foobara_organization!
113
+ exposed_organization.extend(ExposedOrganization)
114
+ exposed_organization.unexposed_organization = org
115
+
97
116
  foobara_register(exposed_organization)
98
117
  exposed_organization.foobara_parent_namespace = self
99
118
 
@@ -7,7 +7,7 @@ module Foobara
7
7
  when Entity
8
8
  # TODO: handle polymorphism? Would require iterating over the result type not the object!
9
9
  # Is there maybe prior art for this in the associations stuff?
10
- unless object.loaded?
10
+ unless object.loaded? || object.built?
11
11
  object.class.load(object)
12
12
  end
13
13
 
@@ -9,6 +9,7 @@ module Foobara
9
9
  TypeDeclarations.register_type_declaration(handler)
10
10
 
11
11
  TypeDeclarations.register_sensitive_type_remover(SensitiveTypeRemovers::DetachedEntity.new(handler))
12
+ TypeDeclarations.register_sensitive_value_remover(handler, SensitiveValueRemovers::DetachedEntity)
12
13
 
13
14
  model = Namespace.global.foobara_lookup_type!(:model)
14
15
  BuiltinTypes.build_and_register!(:detached_entity, model, nil)
@@ -0,0 +1,8 @@
1
+ module Foobara
2
+ class DetachedEntity < Model
3
+ module SensitiveValueRemovers
4
+ class DetachedEntity < Model::SensitiveValueRemovers::Model
5
+ end
6
+ end
7
+ end
8
+ end
@@ -348,12 +348,16 @@ module Foobara
348
348
  # TODO: reuse the model_base_class primary key if it has one...
349
349
  primary_key = attributes_type.element_types.keys.first
350
350
 
351
+ model_module = unless scoped_full_path.empty?
352
+ scoped_full_name
353
+ end
354
+
351
355
  entity_type = foobara_type_builder.type_for_declaration(
352
356
  Util.remove_blank(
353
357
  type: :entity,
354
358
  name:,
355
359
  model_base_class:,
356
- model_module: self,
360
+ model_module:,
357
361
  attributes_declaration: attributes_type_declaration,
358
362
  primary_key:,
359
363
  description:,
@@ -11,6 +11,7 @@ module Foobara
11
11
  TypeDeclarations.register_type_declaration(handler)
12
12
 
13
13
  TypeDeclarations.register_sensitive_type_remover(SensitiveTypeRemovers::Entity.new(handler))
14
+ TypeDeclarations.register_sensitive_value_remover(handler, SensitiveValueRemovers::Entity)
14
15
 
15
16
  detached_entity = Namespace.global.foobara_lookup_type!(:detached_entity)
16
17
  BuiltinTypes.build_and_register!(:entity, detached_entity, nil)
@@ -0,0 +1,20 @@
1
+ module Foobara
2
+ class Entity < DetachedEntity
3
+ module SensitiveValueRemovers
4
+ class Entity < DetachedEntity::SensitiveValueRemovers::DetachedEntity
5
+ def transform(record)
6
+ sanitized_record = super
7
+
8
+ sanitized_record.is_loaded = record.loaded?
9
+ sanitized_record.is_persisted = record.persisted?
10
+
11
+ sanitized_record
12
+ end
13
+
14
+ def build_method
15
+ :build
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -12,9 +12,14 @@ module Foobara
12
12
  TypeDeclarations.register_type_declaration(extended_model_handler)
13
13
 
14
14
  TypeDeclarations.register_sensitive_type_remover(SensitiveTypeRemovers::Model.new(model_handler))
15
+ TypeDeclarations.register_sensitive_value_remover(model_handler, SensitiveValueRemovers::Model)
15
16
  TypeDeclarations.register_sensitive_type_remover(
16
17
  SensitiveTypeRemovers::ExtendedModel.new(extended_model_handler)
17
18
  )
19
+ # TypeDeclarations.register_sensitive_value_remover(
20
+ # extended_model_handler,
21
+ # SensitiveValueRemovers::ExtendedModel
22
+ # )
18
23
 
19
24
  atomic_duck = Namespace.global.foobara_lookup_type!(:atomic_duck)
20
25
  BuiltinTypes.build_and_register!(:model, atomic_duck, nil)
@@ -15,7 +15,7 @@ module Foobara
15
15
  Foobara::Model
16
16
  end
17
17
 
18
- # TODO: considerg splitting this up into multiple desugarizers
18
+ # TODO: consider splitting this up into multiple desugarizers
19
19
  def desugarize(strictish_type_declaration)
20
20
  if strictish_type_declaration.key?(:model_module)
21
21
  model_module = strictish_type_declaration[:model_module]
@@ -79,6 +79,10 @@ module Foobara
79
79
  strictish_type_declaration[:name] = strictish_type_declaration[:name].to_s
80
80
  end
81
81
 
82
+ if strictish_type_declaration[:model_module].nil?
83
+ strictish_type_declaration.delete(:model_module)
84
+ end
85
+
82
86
  strictish_type_declaration[:model_class] ||= [
83
87
  *strictish_type_declaration[:model_module],
84
88
  strictish_type_declaration[:name]
@@ -3,23 +3,46 @@ module Foobara
3
3
  module Handlers
4
4
  class ExtendModelTypeDeclaration < ExtendRegisteredTypeDeclaration
5
5
  class ToTypeTransformer < ExtendRegisteredTypeDeclaration::ToTypeTransformer
6
+ def existing_class_from_same_namespace_root(model_class_name)
7
+ if Object.const_defined?(model_class_name) && Object.const_get(model_class_name).is_a?(::Class)
8
+ existing_class = Object.const_get(model_class_name)
9
+
10
+ # If we are operating in some other namespace tree then we don't want to use the non-anonymous class
11
+ if Domain.current == GlobalDomain || Domain.current.foobara_root_namespace == Foobara::Namespace.global
12
+ return existing_class
13
+ end
14
+
15
+ model_type = existing_class.model_type
16
+
17
+ if model_type
18
+ if model_type.foobara_root_namespace == Foobara::Namespace.current.foobara_root_namespace
19
+ # TODO: test this code path
20
+ # :nocov:
21
+ existing_class
22
+ # :nocov:
23
+ end
24
+ end
25
+ end
26
+ end
27
+
6
28
  # TODO: make declaration validator for model_class and model_base_class
7
29
  def target_classes(strict_type_declaration)
8
30
  model_class_name = strict_type_declaration[:model_class]
9
31
 
10
- if Object.const_defined?(model_class_name) && Object.const_get(model_class_name).is_a?(::Class)
11
- Object.const_get(model_class_name)
12
- else
13
- base_class_name = strict_type_declaration[:model_base_class]
32
+ existing_class = existing_class_from_same_namespace_root(model_class_name)
14
33
 
15
- base_class = if Object.const_defined?(base_class_name)
16
- Object.const_get(base_class_name)
17
- else
18
- foobara_domain.foobara_lookup_type!(base_class_name).target_class
19
- end
20
-
21
- base_class.subclass(name: model_class_name)
34
+ if existing_class
35
+ return existing_class
22
36
  end
37
+
38
+ base_class_name = strict_type_declaration[:model_base_class]
39
+
40
+ base_class = existing_class_from_same_namespace_root(base_class_name)
41
+ base_class ||= lookup_type(base_class_name)&.target_class
42
+ # If we make it here, it's a real base class like Foobara::Entity
43
+ base_class ||= Object.const_get(base_class_name)
44
+
45
+ base_class.subclass(name: model_class_name)
23
46
  end
24
47
 
25
48
  # TODO: must explode if name missing...
@@ -52,7 +75,15 @@ module Foobara
52
75
  # :nocov:
53
76
  else
54
77
  model_class.model_type = type
78
+
79
+ # this is a fairly complex way of making sure that we are getting the domain from the
80
+ # current namespace tree which might not be the case if we're in a command connector
81
+ # namespace
55
82
  domain = model_class.domain
83
+ domain_name = domain.scoped_full_name
84
+ root_namespace = Namespace.current.foobara_root_namespace
85
+ domain = root_namespace.foobara_lookup_domain(domain_name)
86
+
56
87
  type.type_symbol = type.declaration_data[:name]
57
88
  model_class.description type.declaration_data[:description]
58
89
  domain.foobara_register_model(model_class)
@@ -0,0 +1,23 @@
1
+ module Foobara
2
+ class Model
3
+ module SensitiveValueRemovers
4
+ class Model < TypeDeclarations::RemoveSensitiveValuesTransformer
5
+ def transform(record)
6
+ attributes_type = from_type.element_types
7
+
8
+ sanitized_attributes, changed = sanitize_value(attributes_type, record.attributes)
9
+
10
+ if changed
11
+ type.target_class.send(build_method, sanitized_attributes)
12
+ else
13
+ record
14
+ end
15
+ end
16
+
17
+ def build_method
18
+ :new
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -214,14 +214,16 @@ module Foobara
214
214
 
215
215
  return if mode == Namespace::LookupMode::DIRECT
216
216
 
217
- if mode == Namespace::LookupMode::GENERAL
217
+ if [Namespace::LookupMode::GENERAL, Namespace::LookupMode::ABSOLUTE].include?(mode)
218
218
  foobara_children.each do |child|
219
219
  child.foobara_each(filter:, mode:, &)
220
220
  end
221
221
  end
222
222
 
223
- foobara_depends_on_namespaces.each do |dependent|
224
- dependent.foobara_each(filter:, mode:, &)
223
+ if mode == Namespace::LookupMode::GENERAL
224
+ foobara_depends_on_namespaces.each do |dependent|
225
+ dependent.foobara_each(filter:, mode:, &)
226
+ end
225
227
  end
226
228
  end
227
229
 
@@ -111,7 +111,7 @@ module Foobara
111
111
  to_load = Set.new
112
112
 
113
113
  to_load_records.group_by(&:class).each_pair do |entity_class, records|
114
- unloaded = records.reject(&:loaded?)
114
+ unloaded = records.select { |record| record.persisted? && !record.loaded? }
115
115
  entity_class.current_transaction_table.load_many(unloaded)
116
116
 
117
117
  associations = entity_class.associations
@@ -70,7 +70,9 @@ module Foobara
70
70
  @sensitive_type_removers = nil
71
71
 
72
72
  register_sensitive_type_remover(SensitiveTypeRemovers::Attributes.new(attributes_handler))
73
+ register_sensitive_value_remover(attributes_handler, SensitiveValueRemovers::Attributes)
73
74
  register_sensitive_type_remover(SensitiveTypeRemovers::Array.new(array_handler))
75
+ register_sensitive_value_remover(array_handler, SensitiveValueRemovers::Array)
74
76
  end
75
77
 
76
78
  def install!
@@ -0,0 +1,45 @@
1
+ require_relative "typed_transformer"
2
+
3
+ module Foobara
4
+ module TypeDeclarations
5
+ class RemoveSensitiveValuesTransformer < TypedTransformer
6
+ class << self
7
+ def type_declaration(type_declaration)
8
+ if type_declaration.is_a?(Types::Type)
9
+ type_declaration = type_declaration.declaration_data
10
+ end
11
+
12
+ TypeDeclarations.remove_sensitive_types(type_declaration)
13
+ end
14
+ end
15
+
16
+ attr_accessor :namespace
17
+
18
+ def initialize(...)
19
+ super
20
+
21
+ self.namespace = Namespace.current
22
+
23
+ type
24
+ end
25
+
26
+ def transform(_value)
27
+ # :nocov:
28
+ raise "subclass responsibility"
29
+ # :nocov:
30
+ end
31
+
32
+ def sanitize_value(type, value)
33
+ if type.has_sensitive_types?
34
+ remover_class = TypeDeclarations.sensitive_value_remover_class_for_type(type)
35
+ remover = Namespace.use(namespace) { remover_class.new(type) }
36
+ sanitized_value = remover.process_value!(value)
37
+
38
+ [sanitized_value, sanitized_value != value]
39
+ else
40
+ [value, false]
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,30 @@
1
+ module Foobara
2
+ module TypeDeclarations
3
+ module SensitiveValueRemovers
4
+ class Array < RemoveSensitiveValuesTransformer
5
+ def transform(array)
6
+ element_type = from_type.element_type
7
+
8
+ changed = false
9
+
10
+ sanitized_array = array.map do |element|
11
+ sanitized_value, changed2 = sanitize_value(element_type, element)
12
+
13
+ if changed2
14
+ changed = true
15
+ sanitized_value
16
+ else
17
+ element
18
+ end
19
+ end
20
+
21
+ if changed
22
+ sanitized_array
23
+ else
24
+ array
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ require_relative "../remove_sensitive_values_transformer"
2
+
3
+ module Foobara
4
+ module TypeDeclarations
5
+ module SensitiveValueRemovers
6
+ class Attributes < RemoveSensitiveValuesTransformer
7
+ def transform(attributes)
8
+ element_types = from_type.element_types
9
+
10
+ sanitized_attributes = {}
11
+ changed = false
12
+
13
+ attributes.each_pair do |attribute_name, value|
14
+ element_type = element_types[attribute_name]
15
+
16
+ if element_type.sensitive?
17
+ changed = true
18
+ next
19
+ else
20
+ value, changed2 = sanitize_value(element_type, value)
21
+ changed ||= changed2
22
+ sanitized_attributes[attribute_name] = value
23
+ end
24
+ end
25
+
26
+ if changed
27
+ sanitized_attributes
28
+ else
29
+ attributes
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -38,6 +38,28 @@ module Foobara
38
38
  end
39
39
  end
40
40
 
41
+ # TODO: since these are dealing with values instead of declarations maybe this should live somewhere else?
42
+ def register_sensitive_value_remover(handler, sensitive_value_remover)
43
+ sensitive_value_removers[handler.class.name] = sensitive_value_remover
44
+ end
45
+
46
+ def sensitive_value_removers
47
+ @sensitive_value_removers ||= {}
48
+ end
49
+
50
+ def sensitive_value_remover_class_for_type(type)
51
+ handler = GlobalDomain.foobara_type_builder.type_declaration_handler_for(type.declaration_data)
52
+ remover_class = sensitive_value_removers[handler.class.name]
53
+
54
+ unless remover_class
55
+ # :nocov:
56
+ raise "No sensitive value remover found for #{type.declaration_data}"
57
+ # :nocov:
58
+ end
59
+
60
+ remover_class
61
+ end
62
+
41
63
  def strict(&)
42
64
  using_mode(Mode::STRICT, &)
43
65
  end
@@ -20,6 +20,10 @@ module Foobara
20
20
  Foobara::Namespace.current.foobara_lookup_type!(...)
21
21
  end
22
22
 
23
+ def lookup_type(...)
24
+ Foobara::Namespace.current.foobara_lookup_type(...)
25
+ end
26
+
23
27
  def type_registered?(...)
24
28
  Foobara::Namespace.current.foobara_type_registered?(...)
25
29
  end
@@ -31,6 +35,7 @@ module Foobara
31
35
 
32
36
  foobara_delegate :type_for_declaration,
33
37
  :type_declaration_handler_for,
38
+ :lookup_type,
34
39
  :lookup_type!,
35
40
  :lookup_absolute_type!,
36
41
  :type_registered?,
@@ -83,6 +83,24 @@ module Foobara
83
83
  sensitive_exposed
84
84
  end
85
85
 
86
+ def has_sensitive_types?
87
+ return true if sensitive?
88
+
89
+ if element_type
90
+ return true if element_type.has_sensitive_types?
91
+ end
92
+
93
+ if element_types
94
+ types = if element_types.is_a?(::Hash)
95
+ element_types.values
96
+ else
97
+ [*element_types]
98
+ end
99
+
100
+ types.any?(&:has_sensitive_types?)
101
+ end
102
+ end
103
+
86
104
  def apply_all_processors_needing_type!
87
105
  each_processor_class_requiring_type do |processor_class|
88
106
  # TODO: is this a smell?
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foobara
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.81
4
+ version: 0.0.84
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Georgi
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-21 00:00:00.000000000 Z
10
+ date: 2025-03-23 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bigdecimal
@@ -226,6 +226,7 @@ files:
226
226
  - projects/detached_entity/src/extensions/type_declarations/handlers/extend_detached_entity_type_declaration/validate_primary_key_present.rb
227
227
  - projects/detached_entity/src/extensions/type_declarations/handlers/extend_detached_entity_type_declaration/validate_primary_key_references_attribute.rb
228
228
  - projects/detached_entity/src/sensitive_type_removers/detached_entity.rb
229
+ - projects/detached_entity/src/sensitive_value_removers/detached_entity.rb
229
230
  - projects/domain/lib/foobara/domain.rb
230
231
  - projects/domain/src/domain.rb
231
232
  - projects/domain/src/domain_module_extension.rb
@@ -266,6 +267,7 @@ files:
266
267
  - projects/entity/src/new_prepend.rb
267
268
  - projects/entity/src/not_found_error.rb
268
269
  - projects/entity/src/sensitive_type_removers/entity.rb
270
+ - projects/entity/src/sensitive_value_removers/entity.rb
269
271
  - projects/enumerated/lib/foobara/enumerated.rb
270
272
  - projects/enumerated/src/accessors.rb
271
273
  - projects/enumerated/src/enumerated.rb
@@ -316,6 +318,7 @@ files:
316
318
  - projects/model/src/model.rb
317
319
  - projects/model/src/sensitive_type_removers/extended_model.rb
318
320
  - projects/model/src/sensitive_type_removers/model.rb
321
+ - projects/model/src/sensitive_value_removers/model.rb
319
322
  - projects/model_attribute_helpers/lib/foobara/model_attribute_helpers.rb
320
323
  - projects/model_attribute_helpers/src/attribute_helper_aliases.rb
321
324
  - projects/model_attribute_helpers/src/attribute_helpers.rb
@@ -387,9 +390,12 @@ files:
387
390
  - projects/type_declarations/src/handlers/registered_type_declaration/to_type_transformer.rb
388
391
  - projects/type_declarations/src/handlers/registered_type_declaration/type_desugarizer.rb
389
392
  - projects/type_declarations/src/processor.rb
393
+ - projects/type_declarations/src/remove_sensitive_values_transformer.rb
390
394
  - projects/type_declarations/src/sensitive_type_remover.rb
391
395
  - projects/type_declarations/src/sensitive_type_removers/array.rb
392
396
  - projects/type_declarations/src/sensitive_type_removers/attributes.rb
397
+ - projects/type_declarations/src/sensitive_value_removers/array.rb
398
+ - projects/type_declarations/src/sensitive_value_removers/attributes.rb
393
399
  - projects/type_declarations/src/to_type_transformer.rb
394
400
  - projects/type_declarations/src/transformer.rb
395
401
  - projects/type_declarations/src/type_builder.rb