fix: prevent atom exhaustion in merge_projects mix task#3973
fix: prevent atom exhaustion in merge_projects mix task#3973taylordowns2000 merged 8 commits intomainfrom
merge_projects mix task#3973Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3973 +/- ##
==========================================
+ Coverage 88.80% 88.82% +0.01%
==========================================
Files 422 422
Lines 19067 19067
==========================================
+ Hits 16933 16936 +3
+ Misses 2134 2131 -3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Hey @rorymckinley and @josephjclark 👋 This is a new PR that supersedes #3956. Based on Joe's feedback about not coupling the merge task to Provisioner validation or database requirements, I've implemented a much simpler approach. What changed from #3956The new implementation:
How it works
This approach keeps the Mix task decoupled from Lightning's validation constraints while still preventing the atom exhaustion security vulnerability. @josephjclark - As discussed on Slack, this should satisfy your testing needs. When you have time, please test this branch thoroughly and let me know if you see any issues. I've added you as a reviewer. @rorymckinley - When you get a chance, would you be able to help review this and get it merged? I believe this approach is cleaner and aligns better with the Mix task's purpose of being a simple, offline utility. Thanks both! 🙏 |
josephjclark
left a comment
There was a problem hiding this comment.
Not going to pretend to 100% understand what's happening here - but this passes against my test suite, so I'm all for it!
rorymckinley
left a comment
There was a problem hiding this comment.
@elias-ba I have not had a chance to really step through the test changes, will do that tomorrow, but I am shutting down now and don't want to take the chance that github forgets my current comments - so please consider this to be part 1 :).
I have 'Requested Changes' primarily because of my confusion re: Jason.decode - is it sill in the execution path, or are my eyes just tired?
lib/mix/tasks/merge_projects.ex
Outdated
| This may indicate incompatible project structures or corrupted data. | ||
| Please verify both files are valid Lightning project exports. | ||
| """) | ||
| defp atomize_keys(data) when is_list(data) do |
There was a problem hiding this comment.
@elias-ba If I comment out this method, no tests fail - is it still required?
|
@elias-ba Ok, done. If my assessment re: the continued presence of |
Address PR feedback by implementing comprehensive atom safety: - Remove keys: :atoms from Jason.decode to prevent DoS attacks - Rename atomize_keys to atomize for accuracy (atomizes entire structures) - Add ensure_schemas_loaded() to load schema modules before atomization - Use module attribute @required_schemas for maintainable schema list - Add test coverage for ArgumentError rescue on unknown atoms - Optimize schema loading placement (after file validation) This ensures String.to_existing_atom/1 works safely by guaranteeing all schema field atoms (id, name, workflows, etc.) exist in memory before JSON key conversion. Fixes #3615
Consolidates two nearly identical tests that were testing the same functionality with different ID formats. The remaining test now has clearer comments explaining what each assertion verifies. Addresses Rory's feedback about test duplication around lines 9-55 and 704-746 in the test file.
|
@rorymckinley Thanks for the thorough review Rory! You're absolutely right about the blocker - that was embarrassing. I could swear I had removed the For the atom availability concern, great catch. I've added an For the function naming, you're right that Added test coverage for the ArgumentError rescue block - it creates JSON with a dynamically generated field name that won't exist as an atom, verifying the protection mechanism actually works when unknown fields are present. For the UUID validation discussion, since this doesn't involve any database queries we're probably running no risk by allowing non-UUID IDs. The flexibility is useful for Joe's testing scenarios without compromising anything. On test duplication, you were spot on. The "deeply nested structures" test was essentially identical to the basic merge test, just with different ID formats. Removed it and enhanced the remaining test with clearer comments. I also renamed the "works offline without database access" test to "runs standalone without database fixtures" which better describes what it's actually testing. Please could you do another round of review and let me know if you see any other issues! Thanks a lot man for your help |
merge_projects mix task
rorymckinley
left a comment
There was a problem hiding this comment.
@elias-ba Jërëjëf Jambaar! Great work - as Joe has tested the mix task itself, I am not going to delay things by trying to get the setup required for that.
Note: Since the last review, it appears that this PR has gained some typescript files that are unrelated?
|
yeah @rorymckinley , we were supposed to be done with the quote wars ( |
Description
This PR fixes a security vulnerability in the
mix lightning.merge_projectstask where malicious JSON input with arbitrary keys could cause atom exhaustion and crash the VM.The fix uses
String.to_existing_atom/1to safely convert JSON keys to atoms, only allowing keys that already exist in the system. This prevents creation of unlimited atoms from malicious input while maintaining compatibility with the merge algorithm.Closes #3956
Validation steps
Test basic merge functionality:
mix test test/mix/tasks/merge_projects_test.exsAll tests should pass.
Test with non-UUID IDs (Joe's requirement):
Test security:
Test offline operation:
Additional notes for the reviewer
Implementation approach: Uses
atomize_keys/1function that recursively converts only map keys to atoms (not values). UUIDs and other string values remain as strings.No Provisioner coupling: Intentionally does not use
Provisioner.parse_document/1to avoid coupling to validation rules and usage limiting checks (per Joe's feedback).Lets merge fail naturally: If project structure is truly invalid, the merge algorithm itself will fail with appropriate errors rather than blocking upfront.
AI Usage
Please disclose how you've used AI in this work (it's cool, we just want to know!):
You can read more details in our Responsible AI Policy
Pre-submission checklist
:owner,:admin,:editor,:viewer)