Commit 2cdd1ce

mo khan <mo@mokhan.ca>
2026-08-04 02:19:05
fix: keep schema properties named "required" under --attributes
strip_required walked every hash, so an attribute literally named "required" lost its definition and its validation errors were dropped. Keys under "properties" are attribute names, not schema keywords.
cli
1 parent c8b7eff
Changed files (2)
lib
scim
spec
lib/scim/kit/cli/sparse_schema.rb
@@ -16,14 +16,24 @@ module Scim
           def strip_required(value)
             case value
             when Hash
-              value.except('required')
-                .transform_values { |v| strip_required(v) }
+              value.except('required').to_h do |keyword, subschema|
+                [keyword, strip_keyword(keyword, subschema)]
+              end
             when Array
               value.map { |v| strip_required(v) }
             else
               value
             end
           end
+
+          # Keys under 'properties' are attribute names, not schema keywords,
+          # so an attribute named 'required' must not be stripped.
+          def strip_keyword(keyword, subschema)
+            return strip_required(subschema) unless keyword == 'properties'
+            return subschema unless subschema.is_a?(Hash)
+
+            subschema.transform_values { |v| strip_required(v) }
+          end
         end
       end
     end
spec/scim/kit/cli/sparse_schema_spec.rb
@@ -18,7 +18,10 @@ RSpec.describe Scim::Kit::Cli::SparseSchema do
             'type' => 'array',
             'items' => {
               'type' => 'object',
-              'properties' => { 'value' => { 'type' => 'string' } },
+              'properties' => {
+                'value' => { 'type' => 'string' },
+                'required' => { 'type' => 'boolean' }
+              },
               'required' => ['value']
             }
           }
@@ -44,6 +47,13 @@ RSpec.describe Scim::Kit::Cli::SparseSchema do
         .not_to include('required')
     end
 
+    it 'keeps a sub-attribute named required' do
+      relaxed = described_class.relax(schema)
+
+      expect(relaxed['properties']['emails']['items']['properties'])
+        .to include('required' => { 'type' => 'boolean' })
+    end
+
     it 'leaves the original schema untouched' do
       described_class.relax(schema)