Skip to content

Fixes #1327 replacing py2neo with neo4j - #1402

Merged
Rafiot merged 5 commits into
MISP:mainfrom
dewardvide:replace-py2neo-with-neo4j
Mar 21, 2026
Merged

Fixes #1327 replacing py2neo with neo4j#1402
Rafiot merged 5 commits into
MISP:mainfrom
dewardvide:replace-py2neo-with-neo4j

Conversation

@dewardvide

Copy link
Copy Markdown
Contributor

Problem Statement

We need to migrate from py2neo to official neo4j or neomodels driver because py2neo has been deprecated since 2021 as pointed out in issue #1327.

Issue analysis & solution

  • The issue affects pymisp/tools/neo4j.py which migrates events into a Neo4j graph, establishing relationships between the events, attributes and attribute values.
  • Instead of a 1:1 port I made the following architectural changes:
    • I decided to use neo4j because of the simplicity of the script. Using it allows better performance and support because it is the official Neo4j lib
    • By choosing neo4j the Cypher queries were defined directly below is a summarized mapping of the old functions and the new ones:
Aspect py2neo (ORM) neo4j (Cypher)
Connection authenticate() + Graph() GraphDatabase.driver() with Bolt protocol
Node creation Python Node() objects Cypher CREATE (e:Event {$event.uuid})
Relationships Python Relationship() objects Cypher CREATE (a)-[:type]->(b)
Transactions tx.begin() / tx.commit() session.execute_write(callback)
Deduplication tx.merge(subgraph) Cypher MERGE keyword
  • Further implementation details are as follows:

    1. Fixed Protocol & Port: Changed from HTTP (7474) to Bolt (7687) — modern protocol for Neo4j
    2. Added Label Sanitization: MISP attribute types contain special characters (ip-srcdomain|ip). Neo4j label names only accept alphanumeric + underscores. Solution: re.sub(r'[^A-Za-z0-9_]', '_', a.type)
    3. Ensured Resource Safety: Used with context managers to guarantee session/connection cleanup
    4. Parameterized Queries: All parameters use $parameter syntax, preventing Cypher injection
    5. Added Debugging: Warning messages when attribute types are sanitized
    6. Added dependency declaration: Added neo4j = [ "neo4j (>=5.0)" ] to pyproject.toml under optional-dependencies

Testing

  • I created test/test_neo4j.py to test the new version of neo4j.py.
    • The test included the creation of a mock attribute using MISPEvent.add_attribute()
    • Connection to a local neo4j instance
    • Importing the events data using import_event() which is the main function
    • Verifying the event data and their relationships exist
    • Verifying the label sanitation
    • Cleaning up
image *test outcome*
  • All tests were successful!

Disclaimer : AI assisted me in analyzing the issue suggesting different approaches and streamlining testing.

@Rafiot Rafiot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Alright, I did a very quick review of the code and I have a few notes.

Just making sure: you're using neo4j regularly and know what you're doing, right? I have not tested your code yet, this review is simply based on a quick read through.

Comment thread pymisp/tools/neo4j.py Outdated
Comment thread pymisp/tools/neo4j.py Outdated
Comment thread pymisp/tools/neo4j.py Outdated
Comment thread tests/test_neo4j.py Outdated
Comment thread tests/test_neo4j.py Outdated
Comment thread pyproject.toml Outdated

brotli = [ "urllib3[broti] (>=2.6.3)" ]

neo4j = [ "neo4j (>=5.0)" ]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You also need to update the poetry.lock file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, also changed the lowest version to 5.26 to support dynamic labels as in https://neo4j.com/blog/developer/cypher-dynamism/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Quick question on that: why not using the version 6.1 of the package?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

5.6 is the oldest version that supports the changes I made but I've changed it to 6.1 since the neo4j driver docs recommend using the latest driver as it supports older server versions.

Comment thread pymisp/tools/neo4j.py Outdated
@dewardvide

Copy link
Copy Markdown
Contributor Author

Thank you @Rafiot for the valuable feedback. I will look into the comments and respond/make the necessary changes within the course of the week

@Rafiot

Rafiot commented Mar 17, 2026

Copy link
Copy Markdown
Member

That looks great, can you just add the typing markings so mypy is happy? It's not a very big deal, but nice to have.

@dewardvide

Copy link
Copy Markdown
Contributor Author

I've added the types, should be good now

@Rafiot

Rafiot commented Mar 18, 2026

Copy link
Copy Markdown
Member

Can you make sure to update the lock file? I'd like to get the action to pass.

@dewardvide

Copy link
Copy Markdown
Contributor Author

I just realized that I messed something up with the poetry.lock file, I ran poetry update instead of poetry add, let me fix this, I will let you know once it's done

@dewardvide
dewardvide force-pushed the replace-py2neo-with-neo4j branch from 29247a3 to 079c12c Compare March 18, 2026 23:02
@dewardvide

Copy link
Copy Markdown
Contributor Author

Just double checked everything. All should be good now.

@Rafiot
Rafiot merged commit 079c12c into MISP:main Mar 21, 2026
3 of 8 checks passed
@Rafiot

Rafiot commented Mar 21, 2026

Copy link
Copy Markdown
Member

Excellent, thank you very much!

@dewardvide

Copy link
Copy Markdown
Contributor Author

Thank you too! I appreciate the patience and guidance!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants