opa-golib-python-bindings 0.4.3__tar.gz → 0.4.4__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.
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/Makefile +5 -1
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/PKG-INFO +2 -1
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/pyproject.toml +3 -2
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/src/opa_bindings/engine.py +45 -14
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/.gitignore +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/LICENSE +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/README.md +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/go/bridge.go +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/go/bridge_call.c +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/go/builtins.go +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/go/compile.go +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/go/go.mod +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/go/go.sum +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/go/merge.go +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/go/trace.go +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/hatch_build.py +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/src/opa_bindings/__init__.py +0 -0
- {opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/src/opa_bindings/_native.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
LIB := src/opa_bindings/libopabridge.so
|
|
2
2
|
|
|
3
|
-
.PHONY: all build test clean
|
|
3
|
+
.PHONY: all build test fuzz clean
|
|
4
4
|
|
|
5
5
|
all: build
|
|
6
6
|
|
|
@@ -10,5 +10,9 @@ build:
|
|
|
10
10
|
test: build
|
|
11
11
|
python -m pytest tests/ -v
|
|
12
12
|
|
|
13
|
+
FUZZ_EXAMPLES ?= 2000
|
|
14
|
+
fuzz: build
|
|
15
|
+
PYTHONFAULTHANDLER=1 FUZZ_EXAMPLES=$(FUZZ_EXAMPLES) python -m pytest tests/test_fuzz_bindings.py -m fuzz -v
|
|
16
|
+
|
|
13
17
|
clean:
|
|
14
18
|
rm -f $(LIB) src/opa_bindings/libopabridge.h
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: opa-golib-python-bindings
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Summary: Python bindings for the OPA (Open Policy Agent) Rego engine via a Go c-shared library
|
|
5
5
|
Project-URL: Homepage, https://github.com/phi1010/opa-golib-python-bindings
|
|
6
6
|
Project-URL: Repository, https://github.com/phi1010/opa-golib-python-bindings
|
|
@@ -20,6 +20,7 @@ Classifier: Topic :: Security
|
|
|
20
20
|
Classifier: Topic :: Software Development :: Libraries
|
|
21
21
|
Requires-Python: >=3.14
|
|
22
22
|
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: hypothesis; extra == 'dev'
|
|
23
24
|
Requires-Dist: pytest; extra == 'dev'
|
|
24
25
|
Requires-Dist: pyyaml; extra == 'dev'
|
|
25
26
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "opa-golib-python-bindings"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.4"
|
|
4
4
|
description = "Python bindings for the OPA (Open Policy Agent) Rego engine via a Go c-shared library"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -26,7 +26,7 @@ Repository = "https://github.com/phi1010/opa-golib-python-bindings"
|
|
|
26
26
|
Issues = "https://github.com/phi1010/opa-golib-python-bindings/issues"
|
|
27
27
|
|
|
28
28
|
[project.optional-dependencies]
|
|
29
|
-
dev = ["pytest", "pyyaml"]
|
|
29
|
+
dev = ["pytest", "pyyaml", "hypothesis"]
|
|
30
30
|
|
|
31
31
|
[build-system]
|
|
32
32
|
requires = ["hatchling"]
|
|
@@ -53,3 +53,4 @@ include = [
|
|
|
53
53
|
|
|
54
54
|
[tool.pytest.ini_options]
|
|
55
55
|
pythonpath = ["src"]
|
|
56
|
+
markers = ["fuzz: hypothesis fuzz tests of the Python/Go binding layer"]
|
{opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/src/opa_bindings/engine.py
RENAMED
|
@@ -129,7 +129,12 @@ class OpaEngine:
|
|
|
129
129
|
raise OpaError("closed", "engine has been closed")
|
|
130
130
|
|
|
131
131
|
def _call(self, fn, *args):
|
|
132
|
-
|
|
132
|
+
# Read the handle once: another thread may close() the engine after
|
|
133
|
+
# _check_open(). A stale handle is rejected by the Go registry.
|
|
134
|
+
handle = self._handle
|
|
135
|
+
if handle is None:
|
|
136
|
+
raise OpaError("closed", "engine has been closed")
|
|
137
|
+
ptr = fn(handle, *args)
|
|
133
138
|
if not ptr:
|
|
134
139
|
raise OpaError("internal", "native call returned NULL")
|
|
135
140
|
try:
|
|
@@ -174,7 +179,7 @@ class OpaEngine:
|
|
|
174
179
|
except Exception as e: # never let an exception cross into Go
|
|
175
180
|
response = {"error": repr(e)}
|
|
176
181
|
try:
|
|
177
|
-
raw =
|
|
182
|
+
raw = _dumps(response)
|
|
178
183
|
except Exception as e:
|
|
179
184
|
raw = json.dumps({"error": f"unserializable result: {e!r}"}).encode()
|
|
180
185
|
# malloc with the C allocator: ownership of this buffer transfers to
|
|
@@ -194,7 +199,7 @@ class OpaEngine:
|
|
|
194
199
|
def add_policy(self, path: str, source: str):
|
|
195
200
|
"""Add a Rego module under the given path (module name)."""
|
|
196
201
|
self._check_open()
|
|
197
|
-
self._call(self._lib.OpaAddPolicy, path
|
|
202
|
+
self._call(self._lib.OpaAddPolicy, _cstr(path), _cstr(source))
|
|
198
203
|
|
|
199
204
|
def add_data(self, value, path: str = ""):
|
|
200
205
|
"""Deep-merge a JSON-compatible value into the data document.
|
|
@@ -203,7 +208,7 @@ class OpaEngine:
|
|
|
203
208
|
Conflicting existing values raise OpaError(code="merge_conflict").
|
|
204
209
|
"""
|
|
205
210
|
self._check_open()
|
|
206
|
-
self._call(self._lib.OpaAddData, path
|
|
211
|
+
self._call(self._lib.OpaAddData, _cstr(path), _dumps(value))
|
|
207
212
|
|
|
208
213
|
def register_function(self, name: str, fn, *, arity: int | None = None):
|
|
209
214
|
"""Expose a Python callable as a Rego builtin.
|
|
@@ -228,7 +233,7 @@ class OpaEngine:
|
|
|
228
233
|
self._functions[name] = (fn, arity)
|
|
229
234
|
try:
|
|
230
235
|
self._call(
|
|
231
|
-
self._lib.OpaRegisterBuiltin, name
|
|
236
|
+
self._lib.OpaRegisterBuiltin, _cstr(name), arity, self._trampoline
|
|
232
237
|
)
|
|
233
238
|
except Exception:
|
|
234
239
|
del self._functions[name]
|
|
@@ -250,7 +255,7 @@ class OpaEngine:
|
|
|
250
255
|
rs = self._eval_result(
|
|
251
256
|
self._call(
|
|
252
257
|
self._lib.OpaEvalQuery,
|
|
253
|
-
query
|
|
258
|
+
_cstr(query),
|
|
254
259
|
_encode_input(input),
|
|
255
260
|
int(coverage),
|
|
256
261
|
int(trace),
|
|
@@ -275,7 +280,7 @@ class OpaEngine:
|
|
|
275
280
|
rs = self._eval_result(
|
|
276
281
|
self._call(
|
|
277
282
|
self._lib.OpaEvalDocument,
|
|
278
|
-
path
|
|
283
|
+
_cstr(path),
|
|
279
284
|
_encode_input(input),
|
|
280
285
|
int(coverage),
|
|
281
286
|
int(trace),
|
|
@@ -332,18 +337,44 @@ class OpaEngine:
|
|
|
332
337
|
with self._eval_lock:
|
|
333
338
|
envelope = self._call(
|
|
334
339
|
self._lib.OpaCompileFilters,
|
|
335
|
-
query
|
|
340
|
+
_cstr(query),
|
|
336
341
|
_encode_input(input),
|
|
337
|
-
|
|
338
|
-
target
|
|
339
|
-
dialect
|
|
340
|
-
b"" if mappings is None else
|
|
341
|
-
(mask_rule or "")
|
|
342
|
+
_dumps(list(unknowns)),
|
|
343
|
+
_cstr(target),
|
|
344
|
+
_cstr(dialect),
|
|
345
|
+
b"" if mappings is None else _dumps(mappings),
|
|
346
|
+
_cstr(mask_rule or ""),
|
|
342
347
|
)
|
|
343
348
|
return envelope.get("result")
|
|
344
349
|
|
|
345
350
|
|
|
351
|
+
def _cstr(s: str) -> bytes:
|
|
352
|
+
"""Encode a string for a char* argument.
|
|
353
|
+
|
|
354
|
+
Go reads C strings up to the first NUL, so an embedded NUL would silently
|
|
355
|
+
truncate the string (e.g. ``"a\\0b"`` aliasing ``"a"``). Lone surrogates
|
|
356
|
+
are not valid UTF-8 and would be replaced with U+FFFD, letting distinct
|
|
357
|
+
strings collide. Both are rejected.
|
|
358
|
+
"""
|
|
359
|
+
if "\0" in s:
|
|
360
|
+
raise OpaError("invalid_argument", "string contains a NUL character")
|
|
361
|
+
try:
|
|
362
|
+
return s.encode("utf-8")
|
|
363
|
+
except UnicodeEncodeError as e:
|
|
364
|
+
raise OpaError("invalid_argument", f"string is not valid UTF-8: {e}") from None
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def _dumps(value) -> bytes:
|
|
368
|
+
"""Serialize JSON for the Go side. NULs are escaped by json; encoding
|
|
369
|
+
without ensure_ascii makes lone surrogates (which Go would replace with
|
|
370
|
+
U+FFFD) fail instead of being escaped."""
|
|
371
|
+
try:
|
|
372
|
+
return json.dumps(value, ensure_ascii=False).encode("utf-8")
|
|
373
|
+
except UnicodeEncodeError as e:
|
|
374
|
+
raise OpaError("invalid_argument", f"value is not valid UTF-8: {e}") from None
|
|
375
|
+
|
|
376
|
+
|
|
346
377
|
def _encode_input(input):
|
|
347
378
|
if input is None:
|
|
348
379
|
return b""
|
|
349
|
-
return
|
|
380
|
+
return _dumps(input)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/src/opa_bindings/__init__.py
RENAMED
|
File without changes
|
{opa_golib_python_bindings-0.4.3 → opa_golib_python_bindings-0.4.4}/src/opa_bindings/_native.py
RENAMED
|
File without changes
|