oracle-haystack 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/CHANGELOG.md +7 -0
  2. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/PKG-INFO +1 -1
  3. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/src/haystack_integrations/document_stores/oracle/document_store.py +1 -8
  4. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/src/haystack_integrations/document_stores/oracle/filters.py +11 -8
  5. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/tests/test_filter_translator.py +24 -0
  6. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/.gitignore +0 -0
  7. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/README.md +0 -0
  8. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/docker-compose.yml +0 -0
  9. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/init/01_vector_memory.sql +0 -0
  10. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/pydoc/config_docusaurus.yml +0 -0
  11. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/pyproject.toml +0 -0
  12. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/src/haystack_integrations/components/retrievers/oracle/__init__.py +0 -0
  13. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/src/haystack_integrations/components/retrievers/oracle/embedding_retriever.py +0 -0
  14. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/src/haystack_integrations/components/retrievers/oracle/keyword_retriever.py +0 -0
  15. {oracle_haystack-0.2.0/src/haystack_integrations/components/retrievers/oracle → oracle_haystack-0.3.0/src/haystack_integrations/components/retrievers}/py.typed +0 -0
  16. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/src/haystack_integrations/document_stores/oracle/__about__.py +0 -0
  17. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/src/haystack_integrations/document_stores/oracle/__init__.py +0 -0
  18. {oracle_haystack-0.2.0/src/haystack_integrations/document_stores/oracle → oracle_haystack-0.3.0/src/haystack_integrations/document_stores}/py.typed +0 -0
  19. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/tests/__init__.py +0 -0
  20. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/tests/conftest.py +0 -0
  21. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/tests/test_document_store.py +0 -0
  22. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/tests/test_embedding_retriever.py +0 -0
  23. {oracle_haystack-0.2.0 → oracle_haystack-0.3.0}/tests/test_keyword_retriever.py +0 -0
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [integrations/oracle-v0.2.0] - 2026-04-23
4
+
5
+ ### 🚀 Features
6
+
7
+ - Complete `OracleDocumentStore` operations (#3179)
8
+
9
+
3
10
  ## [integrations/oracle-v0.1.0] - 2026-04-16
4
11
 
5
12
  ### 🚀 Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oracle-haystack
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Oracle AI Vector Search DocumentStore integration for Haystack
5
5
  Project-URL: Source Code, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/oracle
6
6
  Project-URL: Bug Tracker, https://github.com/deepset-ai/haystack-core-integrations/issues
@@ -18,21 +18,14 @@ from haystack.document_stores.errors import DocumentStoreError, DuplicateDocumen
18
18
  from haystack.document_stores.types import DuplicatePolicy
19
19
  from haystack.utils import Secret, deserialize_secrets_inplace
20
20
 
21
- from .filters import FilterTranslator
21
+ from .filters import FilterTranslator, _validate_field_path
22
22
 
23
23
  logger = logging.getLogger(__name__)
24
24
 
25
25
  _SAFE_TABLE_NAME = re.compile(r"^[A-Za-z_][A-Za-z0-9_$#]{0,127}$")
26
- _SAFE_FIELD_PATH = re.compile(r"^[A-Za-z0-9_.]+$")
27
26
  MAX_INDEX_NAME_LEN = 128
28
27
 
29
28
 
30
- def _validate_field_path(field_path: str) -> None:
31
- if not _SAFE_FIELD_PATH.match(field_path):
32
- msg = f"Invalid metadata field name: {field_path!r}"
33
- raise ValueError(msg)
34
-
35
-
36
29
  def _try_parse_number(value: Any) -> Any:
37
30
  """
38
31
  Attempt to parse a string as a number.
@@ -2,12 +2,20 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ import re
5
6
  from datetime import datetime
6
7
  from typing import Any, ClassVar
7
8
 
8
9
  from haystack.errors import FilterError
9
10
 
10
11
  _RANGE_OPS = {">", ">=", "<", "<="}
12
+ _SAFE_FIELD_PATH = re.compile(r"^[A-Za-z0-9_.]+$")
13
+
14
+
15
+ def _validate_field_path(field_path: str) -> None:
16
+ if not _SAFE_FIELD_PATH.match(field_path):
17
+ msg = f"Invalid metadata field name: {field_path!r}"
18
+ raise FilterError(msg)
11
19
 
12
20
 
13
21
  class FilterTranslator:
@@ -123,14 +131,9 @@ class FilterTranslator:
123
131
  return "id"
124
132
  if field == "content":
125
133
  return "text"
126
- if field.startswith("meta."):
127
- key = field[len("meta.") :]
128
- json_path = f"JSON_VALUE(metadata, '$.{key}')"
129
- if isinstance(value, (int, float)) and not isinstance(value, bool):
130
- return f"TO_NUMBER({json_path})"
131
- return json_path
132
- # Fallback: treat as top-level JSON key
133
- json_path = f"JSON_VALUE(metadata, '$.{field}')"
134
+ key = field[len("meta.") :] if field.startswith("meta.") else field
135
+ _validate_field_path(key)
136
+ json_path = f"JSON_VALUE(metadata, '$.{key}')"
134
137
  if isinstance(value, (int, float)) and not isinstance(value, bool):
135
138
  return f"TO_NUMBER({json_path})"
136
139
  return json_path
@@ -2,6 +2,9 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ import pytest
6
+ from haystack.errors import FilterError
7
+
5
8
  from haystack_integrations.document_stores.oracle.filters import FilterTranslator
6
9
 
7
10
 
@@ -134,3 +137,24 @@ def test_param_counter_increments_correctly():
134
137
  }
135
138
  )
136
139
  assert set(params.keys()) == {"p0", "p1", "p2"}
140
+
141
+
142
+ def test_sql_injection_via_field_name_raises():
143
+ with pytest.raises(FilterError, match="Invalid metadata field name"):
144
+ _translate({"field": "meta.x') = 'x' OR 1=1 OR ('a", "operator": "==", "value": "y"})
145
+
146
+
147
+ def test_sql_injection_via_fallback_field_raises():
148
+ # Injection via the non-meta fallback path
149
+ with pytest.raises(FilterError, match="Invalid metadata field name"):
150
+ _translate({"field": "x') OR 1=1--", "operator": "==", "value": "y"})
151
+
152
+
153
+ def test_sql_injection_in_not_in_raises():
154
+ with pytest.raises(FilterError, match="Invalid metadata field name"):
155
+ _translate({"field": "meta.x') OR 1=1--", "operator": "in", "value": ["a", "b"]})
156
+
157
+
158
+ def test_valid_nested_field_path_accepted():
159
+ sql, _ = _translate({"field": "meta.author.city", "operator": "==", "value": "Berlin"})
160
+ assert "'$.author.city'" in sql