modelfuzz 0.1.0__tar.gz → 0.1.2__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.
@@ -0,0 +1,27 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(git -C /Users/gagandeep/agentshield status --short --branch)",
5
+ "Bash(uv --version)",
6
+ "Bash(uv sync *)",
7
+ "Bash(uv run python -c ' *)",
8
+ "Bash(uv run *)",
9
+ "Bash(git add *)",
10
+ "Bash(python3 -c \"import modelfuzz; print\\(modelfuzz.__file__\\)\")",
11
+ "Bash(pip show *)",
12
+ "Bash(python3 test_agent.py)",
13
+ "Bash(python3 -c \"import sys; print\\(sys.path\\)\")",
14
+ "Bash(pip list *)",
15
+ "Bash(python3 -c \"import sys,site; print\\(site.getsitepackages\\(\\)\\)\")",
16
+ "Bash(find / -maxdepth 6 -iname \"modelfuzz*\" -not -path \"*/modelfuzz/*\")",
17
+ "Bash(./.venv/bin/pip show *)",
18
+ "Bash(./.venv/bin/python3 test_agent.py)",
19
+ "Bash(python3 -c ' *)",
20
+ "Bash(python3 -m pytest -q)",
21
+ "Bash(./.venv/bin/pip install *)",
22
+ "Bash(./.venv/bin/python test_agent.py)",
23
+ "Bash(python3 -m pip show build twine)",
24
+ "Bash(env)"
25
+ ]
26
+ }
27
+ }
@@ -0,0 +1,46 @@
1
+ # Contributing to ModelFuzz
2
+
3
+ Thanks for your interest in contributing. This document covers how to set up a development environment, run tests, and submit changes.
4
+
5
+ ## Development Setup
6
+
7
+ ModelFuzz uses [uv](https://github.com/astral-sh/uv) for dependency management.
8
+
9
+ ```bash
10
+ git clone https://github.com/higagan/modelfuzz.git
11
+ cd modelfuzz
12
+ uv sync
13
+ ```
14
+
15
+ This installs the package and its dependencies, including dev tools (`pytest`, `ruff`), into a local virtual environment.
16
+
17
+ ## Running Tests
18
+
19
+ ```bash
20
+ uv run pytest
21
+ ```
22
+
23
+ Tests live under [tests/](tests/) and are organized by module (`test_decorator.py`, `test_engine.py`, `test_rules.py`). Add tests alongside the code they cover, and make sure new policies or behaviors are exercised by at least one test.
24
+
25
+ ## Linting
26
+
27
+ ```bash
28
+ uv run ruff check .
29
+ ```
30
+
31
+ CI runs lint and tests against Python 3.10, 3.11, and 3.12 on every push and pull request (see [.github/workflows/ci.yml](.github/workflows/ci.yml)). Please make sure both pass locally before opening a PR.
32
+
33
+ ## Submitting Changes
34
+
35
+ 1. Fork the repository and create a branch from `main`.
36
+ 2. Make your changes, with tests covering new behavior.
37
+ 3. Run `uv run ruff check .` and `uv run pytest` locally.
38
+ 4. Open a pull request describing the change and its motivation.
39
+
40
+ ## Reporting Issues
41
+
42
+ Use [GitHub Issues](https://github.com/higagan/modelfuzz/issues) to report bugs or propose features. Include a minimal reproduction where possible.
43
+
44
+ ## License
45
+
46
+ By contributing, you agree that your contributions will be licensed under the project's [MIT License](LICENSE).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modelfuzz
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Runtime guardrails for AI agents.
5
5
  Project-URL: Homepage, https://github.com/higagan/modelfuzz
6
6
  Project-URL: Repository, https://github.com/higagan/modelfuzz
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "modelfuzz"
3
- version = "0.1.0"
3
+ version = "0.1.2"
4
4
  description = "Runtime guardrails for AI agents."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -0,0 +1,64 @@
1
+ """Decorators for shielding agent tool functions."""
2
+
3
+ import functools
4
+ from collections.abc import Callable
5
+ from typing import ParamSpec, TypeVar, overload
6
+
7
+ from modelfuzz.engine import PolicyEngine
8
+ from modelfuzz.exceptions import ModelFuzzBlockError
9
+ from modelfuzz.rules import SensitiveDataFilter
10
+
11
+ P = ParamSpec("P")
12
+ R = TypeVar("R")
13
+
14
+ # Default policy engine for the decorator
15
+ default_policies = [SensitiveDataFilter()]
16
+ _default_engine = PolicyEngine(default_policies)
17
+
18
+
19
+ @overload
20
+ def shield_tool(engine: Callable[P, R]) -> Callable[P, R]: ...
21
+ @overload
22
+ def shield_tool(
23
+ engine: PolicyEngine | None = None,
24
+ ) -> Callable[[Callable[P, R]], Callable[P, R]]: ...
25
+
26
+
27
+ def shield_tool(engine=None):
28
+ """Wrap a tool function so every call is intercepted before execution.
29
+
30
+ Usable bare (``@shield_tool``) or called (``@shield_tool()`` /
31
+ ``@shield_tool(engine)``).
32
+
33
+ Args:
34
+ engine: The policy engine to use for validation. If None, a default
35
+ engine with a SensitiveDataFilter is used. When applied bare,
36
+ this receives the function being decorated instead.
37
+
38
+ Returns:
39
+ The wrapped function, or a decorator that produces it.
40
+ """
41
+ if callable(engine) and not isinstance(engine, PolicyEngine):
42
+ return _wrap(engine, _default_engine)
43
+
44
+ actual_engine = engine if engine is not None else _default_engine
45
+
46
+ def decorator(func: Callable[P, R]) -> Callable[P, R]:
47
+ return _wrap(func, actual_engine)
48
+
49
+ return decorator
50
+
51
+
52
+ def _wrap(func: Callable[P, R], actual_engine: PolicyEngine) -> Callable[P, R]:
53
+ @functools.wraps(func)
54
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
55
+ # Check all arguments against the policy engine
56
+ for arg in list(args) + list(kwargs.values()):
57
+ result = actual_engine.run(arg)
58
+ if not result.allowed:
59
+ raise ModelFuzzBlockError(result.reason or "Call blocked by policy")
60
+
61
+ print(f"ModelFuzz Intercepted: {func.__name__}")
62
+ return func(*args, **kwargs)
63
+
64
+ return wrapper
@@ -1,12 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(git -C /Users/gagandeep/agentshield status --short --branch)",
5
- "Bash(uv --version)",
6
- "Bash(uv sync *)",
7
- "Bash(uv run python -c ' *)",
8
- "Bash(uv run *)",
9
- "Bash(git add *)"
10
- ]
11
- }
12
- }
@@ -1,45 +0,0 @@
1
- """Decorators for shielding agent tool functions."""
2
-
3
- import functools
4
- from collections.abc import Callable
5
- from typing import ParamSpec, TypeVar
6
-
7
- from modelfuzz.engine import PolicyEngine
8
- from modelfuzz.exceptions import ModelFuzzBlockError
9
- from modelfuzz.rules import SensitiveDataFilter
10
-
11
- P = ParamSpec("P")
12
- R = TypeVar("R")
13
-
14
- # Default policy engine for the decorator
15
- default_policies = [SensitiveDataFilter()]
16
- _default_engine = PolicyEngine(default_policies)
17
-
18
-
19
- def shield_tool(engine: PolicyEngine | None = None) -> Callable[[Callable[P, R]], Callable[P, R]]:
20
- """Wrap a tool function so every call is intercepted before execution.
21
-
22
- Args:
23
- engine: The policy engine to use for validation. If None, a default
24
- engine with a SensitiveDataFilter is used.
25
-
26
- Returns:
27
- A decorator that wraps the function.
28
- """
29
- actual_engine = engine if engine is not None else _default_engine
30
-
31
- def decorator(func: Callable[P, R]) -> Callable[P, R]:
32
- @functools.wraps(func)
33
- def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
34
- # Check all arguments against the policy engine
35
- for arg in list(args) + list(kwargs.values()):
36
- result = actual_engine.run(arg)
37
- if not result.allowed:
38
- raise ModelFuzzBlockError(result.reason or "Call blocked by policy")
39
-
40
- print(f"ModelFuzz Intercepted: {func.__name__}")
41
- return func(*args, **kwargs)
42
-
43
- return wrapper
44
-
45
- return decorator
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes