Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix non-returnables #109

Merged
merged 10 commits into from
Mar 25, 2024
Merged

Fix non-returnables #109

merged 10 commits into from
Mar 25, 2024

Conversation

pond
Copy link
Member

@pond pond commented Mar 18, 2024

Amends a bug introduced in #80 via a variation of suggested fix #103, which reports the quite serious bug that on-create/update attributes like password are being ignored. See #103 for conversation history - TL;DR, looks like as_json was the wrong place and to_scim is the right one for the masking out of non-returnable attributes.

Full credit to @xjunior for #103 and getting the ball rolling on this.

@pond pond added the bug Something isn't working label Mar 18, 2024
#
# ...so all fields, even those marked "returned: false", are included.
# Use Scimitar::Resources::Mixin::to_scim to obtain a SCIM object with
# returnable fields omitted, rendering *that* as JSON via #to_json.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is stil somewhat clear as mud, but at least it gives a fairly strong indication that "you probably don't want to call this for returned JSON data". Between this and the clear examples of controller code in README.md, hopefully it's enough for now.

non_returnable_attributes << 'errors'

original_hash = super(options).except(*non_returnable_attributes)
original_hash = super(options).except('errors')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverts the problematic part of #80.


resource.meta = Meta.new(meta_attrs_hash)
return resource
return self.to_scim_for_returning(location: location)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gives away that we can't actually fully avoid internally the concept of to-SCIM in "render normally" vs "render everything" mode; more info in later diff comments.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's fine for now and more clarity helps in future refactoring.

@@ -417,7 +408,7 @@ def from_scim!(scim_hash:)
#
def from_scim_patch!(patch_hash:)
frozen_ci_patch_hash = patch_hash.with_indifferent_case_insensitive_access().freeze()
ci_scim_hash = self.to_scim(location: '(unused)').as_json().with_indifferent_case_insensitive_access()
ci_scim_hash = self.to_scim_for_patch_op().as_json().with_indifferent_case_insensitive_access()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idiomatic SCIM resource controller code for an #update operation has this at the core:

record = self.find_record(record_id)
record.from_scim_patch!(patch_hash: patch_hash)
self.save!(record, &block)
# ...and render 'record' in SCIM form...

That's how we get to the method being changed here. At the end of this method - you'd need to expand the diff downwards to around new diff line 485 or so - the final steps are:

self.from_scim!(scim_hash: ci_scim_hash)
return self

The idea is that we build ci_scim_hash from the existing data as per the line above, then modify it via whatever update operations are requested, then repopulate the resource from that updated hash. This is related to long-standing issue #6. In lieu of the workload required to produce a true fix, and given that the mixin's tests do include tests to say "if a value is omitted in the Hash then it is set to nil", we can't allow ci_scim_hash to have missing keys due to non-rendered "returned never" attributes. Instead, it must contain them all, so that the current relatively crude (but still, thanks to SCIM's design, very complex) implementation can work as expected.

I note in passing that in the special case of a password, when something like Devise is in use and being used properly (!) then, once a password is written it is encrypted and cannot be read. Attempts to read the password or confirmation return nil; attempts to write nil or empty string have no side effects and are ignored. This is the desired outcome for that attribute. It does open up the question of non-password "returned never" attributes where the underling model might not allow a read operation, though, causing set-to-nil behaviour in subsequent SCIM patch updates.

TL;DR, what a mess. But this gets us by for now, and resolves issues highlighted by the updated tests.

@pond pond marked this pull request as ready for review March 19, 2024 00:22
@pond
Copy link
Member Author

pond commented Mar 19, 2024

@xjunior This is ready to be looked at now. I've annotated the diff with a few comments. It's interesting to see that a reliable, deep fix would only be possible with issue #6 addressed, but as-is, unless people are using very weird schema, it should do just fine for common user and group management workloads.

@xjunior
Copy link
Contributor

xjunior commented Mar 19, 2024

Awesome, @pond! I have seen the issue #6, but didn't have a chance to deeply analyze it. I plan to do so soon, as we are and will be relying a lot on Scimitar.

@pond
Copy link
Member Author

pond commented Mar 21, 2024

Converted back to draft after a giant rabbit hole opened, in which a hundred yaks in need of shaving.

@pond pond marked this pull request as ready for review March 25, 2024 04:17
@pond
Copy link
Member Author

pond commented Mar 25, 2024

@xjunior this is - I think! - ready for review now. In addition, but only if you have time, please could you try using this in your Gemfile to load Scimitar from PR 109's branch directly and see if that's doing what you need? Our own tests pass this way but they've never exercised as many features or edge cases as some of the gem's contributors evidently have!

gem 'scimitar', git: 'https://github.com/RIPAGlobal/scimitar', branch: 'feature/fix-non-returnables'

@xjunior
Copy link
Contributor

xjunior commented Mar 25, 2024

@pond I just ran my test suite with this branch and my specs are passing without the hacks I had.

Copy link
Member

@sierra-alpha sierra-alpha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That casing of the keys work seems like a good head scratch but looks like it's well tested! Just a few typos that I could see.

app/models/scimitar/resources/mixin.rb Outdated Show resolved Hide resolved
pond and others added 2 commits March 26, 2024 10:10
Co-authored-by: Shaun Alexander <37967220+sierra-alpha@users.noreply.github.com>
…cess.rb

Co-authored-by: Shaun Alexander <37967220+sierra-alpha@users.noreply.github.com>
@pond pond merged commit 150d64a into main Mar 25, 2024
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants