Skip to content

Enforce read-only Hive queries at the Bolt transaction level; map DB write rejection to 403 - #1611

Merged
Evanfeenstra merged 3 commits into
mainfrom
feature/cmtbqyv180009l104kbww5jfk-read-mode-bolt-transaction-403-1787916267
Aug 28, 2026
Merged

Enforce read-only Hive queries at the Bolt transaction level; map DB write rejection to 403#1611
Evanfeenstra merged 3 commits into
mainfrom
feature/cmtbqyv180009l104kbww5jfk-read-mode-bolt-transaction-403-1787916267

Conversation

@tomsmith8

Copy link
Copy Markdown
Collaborator

Summary

  • Route hive queries through read-mode Bolt transactions by enforcing read-only access at the Neo4j transaction level in graph_ops
  • Map Neo4j write rejection to an HTTP 403 response with a dedicated error variant in shared/src/error.rs
  • Extend the hive query handler and types to surface the 403 on write attempts
  • Add integration tests in standalone/tests/hive_read_only.rs

Generated with Hive

…write rejection to 403

GraphOps::execute_raw_cypher now runs through neo4rs execute_read() (Bolt
autocommit mode "r"), so Neo4j itself refuses any write — including write
procedures invoked via CALL, which the keyword denylist cannot generally
catch. Database-level rejections (Neo.ClientError.Statement.AccessMode,
or ProcedureCallFailed wrapping an access-mode violation) surface as
shared::Error::ReadOnlyViolation and map to HTTP 403 in the Hive handler
with the same body as the denylist rejection; warn! logs carry the Neo4j
error code and query length (never the query body) at both boundaries.
The denylist, forced LIMIT, and 4096-char cap stay as defense-in-depth,
and the previously false 'read-mode transaction' comments now describe
the real implementation.

A test-only hive_query_handler_denylist_bypassed entry point (not wired
into the router) lets the integration test prove the guarantee comes
from the database: with the denylist disabled, CREATE and
CALL apoc.create.node probes both return 403 and leave no trace in the
graph, while MATCH and read-only procedures keep working (200). Verified
against live Neo4j 5.19.
@Evanfeenstra
Evanfeenstra merged commit 277dcb8 into main Aug 28, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants